Hi Gábor,

This is looking good to me.  Some minor nits/comments:

- Please add doxygen comments for the CodeInjector class.
- For the BugReporter patch, are there tests for that functionality change?  I 
saw tests in the other patch, but not that one.  It's fine to separate the 
review of that change before the primary change goes in, but I was curious.
- As for breaking code in the 'extra' repository, LLVM-internal API is not 
sacrosanct.  If we break the 'extra' projects we just need to update them, but 
I'm not certain if that is possible in this case.
- For comments, please consistently use sentence casing and end with periods, 
and for type names use the appropriate casing.  For example:

+  // modules create a separate compilerinstance for parsing modules, maybe it 
is
+  // for reason so I mimic this behavior
+  CompilerInstance Instance;
...

This comment looks a bit suspect, since it seems like a question to yourself.  
Here you use the word "I"; who is "I" in the context of this code?  The comment 
also seems like an unanswered question.  Is this a stale comment?

Another example is this comment:

+  // FIXME: double memoization is redundant. Here and in bodyfarm.
+  llvm::StringMap<Stmt *> Bodies;

This can be made slightly cleaner.  For example:

+  // FIXME: Double memorization is redundant, with
+  /// memoization both here and in BodyFarm.
+  llvm::StringMap<Stmt *> Bodies;


- Only use doxygen comments for documentation.  For example:

+  if (notzero_notmodeled(p)) {
+   /// There is no information about the value of p, because
+   /// notzero_notmodeled is not modeled and the function definition
+   /// is not available.
+    int j = 5 / p; // expected-warning {{Division by zero}}
+  }

In this case we should use '//', not '///'.  The former are true comments, and 
the latter are candidates to be extracted for documentation.

Overall, however, this is getting really close.

Cheers,
Ted

On Jul 30, 2014, at 3:29 AM, Gábor Horváth <[email protected]> wrote:

> Hi Ted,
> 
> Thank you for the review.
> 
> 
> On 30 July 2014 08:18, Ted Kremenek <[email protected]> wrote:
> Hi Gábor,
> 
> Thanks for making progress on this very promising enhancement to the 
> analyzer.  I have an assortment of comments, in no particular order:
> 
> - ModelInjector.h and ModelConsumer.h
> 
> There is a comment at the top of these files, but I think a bit more 
> explanation is needed.  For example:
> 
>   MetaConsumer.cpp:
> 
>     +// "Meta" ASTConsumer for consuming model files.
> 
> That doesn't really explain anything.  What does "Meta" in quotes mean?  I 
> think an explanation here on what this does is helpful when someone discovers 
> this code for the first time.
> 
> Similarly, we should add some high-level comments for CodeInjector.h and 
> ModelInjector.h.  We have a good start in ModelInjector.h:
> 
> +/// \file
> +/// \brief Defines the clang::ento::ModelInjector class which implements the
> +/// clang::CodeInjector interface. This class is responsible for injecting
> +/// function definitions that were synthetized from model files.
> +///
> 
> Let's consider expanding it:
> 
>  /// \brief This file defines the clang::ento::ModelInjector class which 
> implements the
>  /// clang::CodeInjector interface. This class is responsible for injecting
>  /// function definitions that were synthesized from model files.
> 
>  /// Model files allow definitions of functions to be lazily constituted for 
> functions
>  /// which lack bodies in the original source code.  This allows the analyzer
>  /// to more precisely analyze code that calls such functions, analyzing the
>  /// artificial definitions (which typically approximate the semantics of the
>  /// called function) when called by client code.  These definitions are
>  /// reconstituted lazily, on-demand, by the static analyzer engine.
> 
> CodeInjector.h provides some information, but it is a bit vague:
> 
> +///
> +/// \file
> +/// \brief Defines the clang::CodeInjector interface which is responsible for
> +/// injecting AST of function definitions from external source.
> +///
> 
> It's a bit unclear how this gets used.  I think a bit of prose here would 
> help clarify its role in the static analyzer.  I also think the CodeInjector 
> interface is also more abstract than the prose describes.  There's nothing 
> about CodeInjector's interface that requires the injected definitions to come 
> from an external source.  That's an implementation detail of a concrete 
> subclass.  Instead, all CodeInjector does is provide an interface that lazily 
> provides definitions for functions and methods that may not be present in the 
> original source.
> 
> I have added some further documentation to address these issues.
> 
>  
> 
> I'm also looking at the change to 
> StaticAnalyzer/Frontend/FrontendActions.cpp, and wonder if we can simplify 
> things:
> 
>> +++ lib/StaticAnalyzer/Frontend/FrontendActions.cpp (working copy)
>> @@ -7,9 +7,11 @@
>>  //
>>  
>> //===----------------------------------------------------------------------===//
>>  
>> +#include "clang/Frontend/CompilerInstance.h"
>>  #include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
>> -#include "clang/Frontend/CompilerInstance.h"
>>  #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
>> +#include "clang/StaticAnalyzer/Frontend/ModelConsumer.h"
>> +#include "ModelInjector.h"
>>  using namespace clang;
>>  using namespace ento;
>>  
>> @@ -18,6 +20,14 @@
>>    return CreateAnalysisConsumer(CI.getPreprocessor(),
>>                                  CI.getFrontendOpts().OutputFile,
>>                                  CI.getAnalyzerOpts(),
>> -                                CI.getFrontendOpts().Plugins);
>> +                                CI.getFrontendOpts().Plugins,
>> +                                new ModelInjector(CI));
>>  }
>>  
> 
> 
> It looks like CreateAnalysisConsumer just continues to grow more arguments, 
> all which derive from using 'CI'.  This seems silly, since this function is 
> called in one place.  Instead of intro ducting a dependency on 
> ModelInjector.h in this file, we can just sink these arguments into 
> CreateAnalysisConsumer() itself, resulting in:
> 
>   return CreateAnalysisConsumer(CI);
> 
> and let CreateAnalysisConsumer() do all that boilerplate.
> 
> That was my original idea as well but it broke the compilation of some code 
> in extra repository and I wasn't sure if it is ok to break the API with this 
> patch. But I find it cleaner this way so I modified it in this iteration.
> 
> 
> Next, let's look at the change to FrontendAction:
> 
>>  class FrontendAction {
>> +  /// Is this action invoked on a model file? Model files are incomplete
>> +  /// translation units that relies on type information from another 
>> translation
>> +  /// unit. Check ParseModelFileAction for details.
>> +  bool ModelFile;
> 
> Perhaps "IsModelFile"?  "ModelFile" sounds like it should be a reference to 
> the file itself.
> 
>>    FrontendInputFile CurrentInput;
>>    std::unique_ptr<ASTUnit> CurrentASTUnit;
>>    CompilerInstance *Instance;
>> @@ -105,7 +109,11 @@
>>    /// @}
>>  
>>  public:
>> -  FrontendAction();
>> +  /// \brief Constructor
>> +  ///
>> +  /// \param modelFile determines whether the source files this action 
>> invoked
>> +  /// on should be treated as a model file. Defaults to false.
>> +  FrontendAction(bool modelFile = false);
> 
> It seems suboptimal to modify the interface of FrontendAction just for this 
> one edge case.  Instead of modifying the constructor arguments, we could 
> default initialize "IsModelFile" to false, and have a setter to change it.  
> For example:
> 
>   ParseModelFileAction::ParseModelFileAction(llvm::StringMap<Stmt *> &Bodies)
>     : ASTFrontendAction(/*ModelFile=*/true), Bodies(Bodies) {}
> 
> becomes:
>  
>   ParseModelFileAction::ParseModelFileAction(llvm::StringMap<Stmt *> &Bodies)
>     : Bodies(Bodies)  {
>     IsModelFile = true;
>   }
> 
> Looking at this more, I wonder if we should modify FrontendAction at all.  
> The only place where isModelParsingAction() is called is in one spot in 
> CompilerInstance.cpp:
> 
>    if (hasSourceManager() && !Act.isModelParsingAction())
> 
> It *might* be cleaner to just have a virtual member function in 
> FrontendAction, which defaults to returning false, but is generic for all 
> subclasses to override.  Then we don't need the "IsModelFile" field in 
> FrontendAction at all, and we just have ParseModelFileAction override that 
> single member function.  We could then name that method to be something a bit 
> more generic.  That would allow us to not touch FrontendAction at all except 
> for providing that single virtual method that can be overridden in 
> subclasses.  I somewhat prefer this approach because it provides a cleaner 
> separation of concerns between FrontendAction (which is defined libFrontend) 
> and the static analyzer.  That would also allow you to get rid of 
> isModelParsingAction() entirely (replacing it with something more generic).
> 
> 
> You are right, it is much cleaner to use a virtual function, so I modified 
> the patch to use that approach. The new virtual function has the same name 
> because I have yet to find any better and more general name yet. Do you have 
> an idea for a better name?
>  
> As for the test case:
> 
>> +typedef int* intptr;
>> +
>> +void modelled(intptr p);
>> +
>> +int main() {
>> + modelled(0);
>> + return 0;
>> +}
> 
> Please add some comments in this test file explaining what is happening.  
> Also, it would be great if this both used FileCheck (which it does now) but 
> also verified the diagnostics so we get cross-checking of the output (we see 
> this in some analyzer tests).  It also makes it easier to understand the test.
> 
> Also, is there a reason to break up the tests between 
> model-suppress-falsepos.cpp and model-file.cpp?  It seems like one test file 
> will do fine; just clearly comment on what is happening for each test.  I 
> also recommend called the modeled function "modeledFunction" instead of 
> "modelled" (which according to my spell checker has an additional 'l'). 
> 
> I have merged the test files and also added some commets to explain what is 
> going on. I have fixed the misspelling as well. The nullpointer dereference 
> is only checked through plist because the point where the comment with the 
> expected warning should be added is inside the model file and it did not work 
> for me if the comment was in a separate file. If there is a different way to 
> verify the warnings that are in a separate file and I did not find it, please 
> let me know.
>  
> 
> As for the model files themselves:
> 
>> Index: test/Analysis/modelled.model
>> ===================================================================
>> --- test/Analysis/modelled.model  (revision 0)
>> +++ test/Analysis/modelled.model  (working copy)
>> @@ -0,0 +1,3 @@
>> +void modelled(intptr p) {
>> + ++*p;
>> +}
>> \ No newline at end of file
>> Index: test/Analysis/notzero.model
>> ===================================================================
>> --- test/Analysis/notzero.model (revision 0)
>> +++ test/Analysis/notzero.model (working copy)
> 
> Let's put these in a separate subdirectory, for example, "models", instead of 
> mixing them with the tests.  This way they really serve as "inputs" to the 
> analyzer.
> 
> I have moved the model files to tests/Inputs/Models.
>  
> 
> Overall this is looking good.  I think the explanatory comments will really 
> help people understand what this is doing, and I think changing how we thread 
> the information through FrontendAction will help not introduce an artificial 
> tainting of FrontendAction with concepts specific to the static analyzer.
> 
> Cheers,
> Ted
> 
> 
> Thanks,
> Gábor
>  
> 
> On Jul 16, 2014, at 2:45 AM, Gábor Horváth <[email protected]> wrote:
> 
>> 
>> 
>> 
>> On 14 July 2014 19:32, Anna Zaks <[email protected]> wrote:
>> 
>>> On Jul 13, 2014, at 6:11 AM, Gábor Horváth <[email protected]> wrote:
>>> 
>>> Hi Anna,
>>> 
>>> Thank you for the review. I have tweaked the test, so it no longer requires 
>>> the error reporting tweak that is not done yet to pass. I have also added 
>>> some high level comments to some files, if you think some information is 
>>> lacking I will add them in the next iteration as well. The BugReporter 
>>> patch is now separated into a different patch. 
>>> 
>>> 
>>> On 11 July 2014 18:02, Anna Zaks <[email protected]> wrote:
>>> 
>>> For example, modeling functions should allow you to find bugs and suppress 
>>> false positives outside of those functions. I would suggest adding a few of 
>>> those tests first.
>>> 
>>> 
>>> How are the false positives suppressed? I did not find any resource on 
>>> that. Found some analyzer attributes but I did not find them suitable for 
>>> this purpuse at the first glance. But I think once the locations that are 
>>> in a model file are omitted from the report path, the regular methods for 
>>> suppressing false positives should work (and I will definitely add test 
>>> case to ensure this once it is done).
>>> 
>> 
>> What I meant is that it is possible to construct a test where ability to 
>> model a function would eliminate a false positive. This would be another way 
>> to test your patch without worrying about BugReporter.
>> 
>> I got it now, thansk. I have updated the patch with a test case where a 
>> false positive case is eliminated by a model file.
>> 
>> Thanks,
>> Gábor
>>  
>>> Thanks,
>>> Gábor
>>> <api_modeling.patch><bugreporter.patch>
>> 
>> 
>> <api_modeling.patch><bugreporter.patch>
> 
> 
> <api_modeling.patch><bugreporter.patch>

_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to