Find unimplemented class methods
Asked Answered
F

8

10

In my application, I'm dealing with a larger-size classes (over 50 methods) each of which is reasonably complex. I'm not worried about the complexity as they are still straight forward in terms of isolating pieces of functionality into smaller methods and then calling them. This is how the number of methods becomes large (a lot of these methods are private - specifically isolating pieces of functionality).

However when I get to the implementation stage, I find that I loose track of which methods have been implemented and which ones have not been. Then at linking stage I receive errors for the unimplemented methods. This would be fine, but there are a lot of interdependencies between classes and in order to link the app I would need to get EVERYTHING ready. Yet I would prefer to get one class our of the way before moving to the next one.

For reasons beyond my control, I cannot use an IDE - only a plain text editor and g++ compiler. Is there any way to find unimplemented methods in one class without doing a full linking? Right now I literally do text search on method signatures in the implementation cpp file for each of the methods, but this is very time consuming.

Florinda answered 14/1, 2013 at 10:37 Comment(4)
What prevents you from simply attempting to link and grepping for the "undefined reference to " message?Stapes
Yes, that's one way of doing it, but I'll get a lot of these that may not relate to the class in question. The overall project has hundreds of classes and the build takes about 30 minutes.Florinda
I suspected it would be the pure quantity which may pose a problem. However, you should be able to grep for "undefined reference to ClassInQuestion::", to only get hits for methods from that class. (I'll make an answer stating the same)Stapes
perhaps you can somehow use regex and find <methodname> in the .h file and then look for <myclass>::<methodname> in the cpp file? My regex skills are unfortunately worthless though :PDoss
S
0

Though I can't see a simple way of doing this without actually attempting to link, you could grep the linker output for "undefined reference to ClassInQuestion::", which should give you only lines related to this error for methods of the given class.

This at least lets you avoid sifting through all error messages from the whole linking process, though it does not prevent having to go through a full linking.

Stapes answered 14/1, 2013 at 11:41 Comment(2)
Yeah, from the automated point of view this seems to be the simplest approach. The biggest issue now is the 30+ minutes that the build takes...Florinda
@AleksG That is indeed an issue, and with that in place I cannot find a suitable solution other than writing a tool for comparing the .h and .cpp files, looking for matching/missing function declarations and definitions.Stapes
A
3

You could add a stub for every method you intend to implement, and do:

void SomeClass::someMethod() {
    #error Not implemented
}

With gcc, this outputs file, line number and the error message for each of these. So you could then just compile the module in question and grep for "Not implemented", without requiring a linker run.

Although you then still need to add these stubs to the implementation files, which might be part of what you were trying to circumvent in the first place.

Alithea answered 14/1, 2013 at 11:50 Comment(3)
But this still requires me to implement all methods. Moreover, I need to be able to compile a non-complete class to check for syntax errors, etc. before everything is ready.Florinda
Well, that's true. Although you could add all the stubs and then start implementing, and you'd have an easy way to see which methods are still stubs. But I see how it may not be exactly what you're looking for.Alithea
Maybe you can write a short add_method python script or something, which inserts the above stub at the end of a cpp file? Should not be too hard, unless you use different namespace nesting levels in different files..Alithea
S
0

Though I can't see a simple way of doing this without actually attempting to link, you could grep the linker output for "undefined reference to ClassInQuestion::", which should give you only lines related to this error for methods of the given class.

This at least lets you avoid sifting through all error messages from the whole linking process, though it does not prevent having to go through a full linking.

Stapes answered 14/1, 2013 at 11:41 Comment(2)
Yeah, from the automated point of view this seems to be the simplest approach. The biggest issue now is the 30+ minutes that the build takes...Florinda
@AleksG That is indeed an issue, and with that in place I cannot find a suitable solution other than writing a tool for comparing the .h and .cpp files, looking for matching/missing function declarations and definitions.Stapes
C
0

In the past I have built an executable for each class:

#include "klass.h"
int main() {
    Klass object;
    return 0;        
}

This reduces build time, can let you focus on one class at a time, speeds up your feedback loop.

It can be easily automated.

I really would look at reducing the size of that class though!

edit

If there are hurdles, you can go brute force:

#include "klass.h"

Klass createObject() {
    return *reinterpret_cast<Klass>(0);
}    

int main() {
    Klass object = createObject();
    return 0;        
}
Carouse answered 14/1, 2013 at 12:28 Comment(5)
Of course that only works for classes with default constructors (or at least only those that don’t depend on other classes), and it won’t verify that all functions are implemented.Kynthia
You can automate it without default constructors. You include the object files necessary to make it link. It verifies all virtual functions have been implemented. This is the outline of the idea, not a full implementation.Carouse
That would be nice if Klass didn't depend on 50 other classes to compile.Florinda
@AleksG That sounds like a serious error in the class design, to be honest.Kynthia
This is a green room idea. Work out how to do it yourself!Carouse
K
0

That’s what unit tests and test coverage tools are for: write minimal tests for all functions up-front. Tests for missing functions won’t link. The test coverage report will tell you whether all functions have been visited.

Of course that’s only helping up to some extent, it’s not a 100% fool proof. Your development methodology sounds slightly dodgy to me though: developing classes one by one in isolation doesn’t work in practice: classes that depend on each other (and remember: reduce dependencies!) need to be developed in lockstep to some extent. You cannot churn out a complete implementation for one class and move to the next, never looking back.

Kynthia answered 14/1, 2013 at 12:41 Comment(2)
I don't want to "visit" every function. I want, at editing stage, to see what I have not implemented. To run unit tests, I need to compile and link - and the whole point of my question was to see if there a way to find missing implementations without linking.Florinda
@Aleks Well sure there is. In an IDE. Which you explicitly don’t want. And sure, there are other tools to also give you that information. My answer describes them.Kynthia
L
0

You could write a small script which analyses the header file for method implementations (regular expressions will make this very straightforward), then scans the implementation file for those same method implementations.

For example in Ruby (for a C++ compilation unit):

className = "" # Either hard-code or Regex /class \w+/
allMethods = []

# Scan header file for methods
File.open(<headerFile>, "r") do |file|
    allLines = file.map { |line| line }
    allLines.each do |line|
        if (line =~ /(\);)$/) # Finds lines ending in ");" (end of method decl.)
            allMethods << line.strip!
        end
    end
end

implementedMethods = []
yetToImplement = []

# Scan implementation file for same methods
File.open(<implementationFile>, "r") do |file|
    contents = file.read
    allMethods.each do |method|
        if (contents.include?(method)) # Or (className + "::" + method)
            implementedMethods << method
        else
            yetToImplement << method
        end
    end
end

# Print the results (may need to scroll the code window)
print "Yet to implement:\n"
yetToImplement.each do |method|
    print (method + "\n")
end

print "\nAlready implemented:\n"
implementedMethods.each do |method
    print (method + "\n")
end

Someone else will be able to tell you how to automate this into the build process, but this is one way to quickly check which methods haven't yet been implemented.

Lolalolande answered 14/1, 2013 at 23:8 Comment(0)
G
0

The delete keyword of c++11 does the trick

struct S{
  void f()=delete; //unimplemented
};

If C++11 is not avaiable, you can use private as a workaround

struct S{
  private: //unimplemented
  void f();
};

With this two method, you can write some testing code in a .cpp file

//test_S.cpp
#include "S.hpp"
namespace{
  void test(){
    S* s;
    s->f(); //will trigger a compilation error
  }
}

Note that your testing code will never be executed. The namespace{} says to the linker that this code is never used outside the current compilation unit (i.e., test_S.cpp) and will therefore be dropped just after compilation checking.

Because this code is never executed, you do not actualy need to create a real S object in the test function. You just want to trick the compiler in order to test if a S objects has a callable f() function.

Grasshopper answered 16/12, 2014 at 11:39 Comment(0)
A
0

You can create a custom exception and throw it so that:

  • Calling an unimplemented function will terminate the application instead of leaving it in an unexpected state
  • The code can still be compiled, even without the required functions being implemented
  • You can easily find the unimplemented functions by looking through compiler warnings (by using some possibly nasty tricks), or by searching your project directory
  • You can optionally remove the exception from release builds, which would cause build errors if there are any functions that try to throw the exception
#if defined(DEBUG)

#if defined(__GNUC__)
#define DEPRECATED(f, m) f __attribute__((deprecated(m)))
#elif defined(_MSC_VER)
#define DEPRECATED(f, m) __declspec(deprecated(m)) f
#else
#define DEPRECATED(f, m) f
#endif

class not_implemented : public std::logic_error {
public:
    DEPRECATED(not_implemented(), "\nUnimplemented function") : logic_error("Not implemented.") { }
}

#endif // DEBUG

Unimplemented functions would look like this:

void doComplexTask() {
    throw not_implemented();
}

You can look for these unimplemented functions in multiple ways. In GCC, the output for debug builds is:

main.cpp: In function ‘void doComplexTask()’:
main.cpp:21:27: warning: ‘not_implemented::not_implemented()’ is deprecated: 
Unimplemented function [-Wdeprecated-declarations]
     throw not_implemented();
                           ^
main.cpp:15:16: note: declared here
     DEPRECATED(not_implemented(), "\nUnimplemented function") : logic_error("Not implemented.") { }
                ^~~~~~~~~~~~~~~
main.cpp:6:26: note: in definition of macro ‘DEPRECATED’
 #define DEPRECATED(f, m) f __attribute__((deprecated(m)))

Release builds:

main.cpp: In function ‘void doComplexTask()’:
main.cpp:21:11: error: ‘not_implemented’ was not declared in this scope
     throw not_implemented;
           ^~~~~~~~~~~~~~~

You can search for the exception with grep:

$ grep -Enr "\bthrow\s+not_implemented\b"
main.cpp:21:    throw not_implemented();

The advantage of using grep is that grep doesn't care about your build configuration and will find everything regardless. You can also get rid of the deprecated qualifier to clean up your compiler output--the above hack generates a lot of irrelevant noise. Depending on your priorities this might be a disadvantage (for example, you might not care about Windows-specific functions if you're currently implementing Linux-specific functions, or vice-versa.)

If you use an IDE, most will let you search your entire project, and some even let you right-click a symbol and find everywhere it is used. (But you said you can't use one so in your case grep is your friend.)

Academician answered 5/6, 2018 at 4:26 Comment(0)
A
-1

I cannot see an easy way of doing this. Having several classes with no implementation will easily lead to a situation where keeping track in a multiple member team will be a nightmare.

Personally I would want to unit test each class I write and test driven development is my recommendation. However this involves linking the code each time you want to check the status. For tools to use TDD refer to link here.

Another option is to write a piece of code that can parse through the source and check for functihat are to be implemented. GCC_XML is a good starting point.

Aquino answered 14/1, 2013 at 10:59 Comment(9)
Please let me know the reason for the down vote. Will help me understand better. ThanksAquino
This would mean actually implementing every function, which would let it link, but move the problem to run-time. This is not always desirable in a large project. It forces TDD, which may not be a possible transition (since it puts demands on the project as a whole).Stapes
Another possibility along the same lines would be to initially implement functions as dummies with a static_assert(false,"unimplemented function") for those that -need- to be implemented.Stapes
I work on a project that has 3 million lines of code and we use TDD. I am sorry but I disagree with your comment on large project. Test Driven Development is one of the best ways to isolate and manage complexity. It also helps me keep track of what is left to do.Aquino
I'm not saying that it cannot be used on a big project, I think it's excellent in large projects, for the reasons you've stated. But, beginning with TDD can be a management decision that a lone programmer isn't able to take. In which case such general advice doesn't provide any practical use.Stapes
The issue with this approach is that it still requires linking. My question was: Is there any way to find unimplemented methods in one class without doing a full linking?Florinda
@AleksG Agreed. It is difficult if not impossible to write a piece of code that parses a translation unit file and report the presence or absence of the function implementation. I can try it in my free time and it may not take long.Aquino
@Aquino Feel free to do that, however my question was about whether there's a way to do what I want. "There is no way" is also a valid answer.Florinda
@AlexsG You may be right. I was wondering if GCC-XML could help you write something quickly. Just a thought. gccxml.org/HTML/Index.htmlAquino

© 2022 - 2024 — McMap. All rights reserved.