Commit 28c1b109 authored by thakis's avatar thakis Committed by Commit bot

win: Make oilpan plugin work better with delayed template parsing.

On Windows, clang-cl only parses template methods that are
referenced (-fdelayed-template-parsing), so members traced from
unreferenced template methods weren't seen by the plugin, which
caused it to warn about them.

Explicitly parse delayed template methods that look like they
are trace methods and that aren't in system headers to work around
this. This is based on Kim Grasman's patch for the IWYU project:
https://code.google.com/p/include-what-you-use/source/detail?r=566

This fixes 3 of the 4 failing oilpan plugin tests on Windows.

BUG=486571
NOPRESUBMIT=true

Review URL: https://codereview.chromium.org/1140443005

Cr-Commit-Position: refs/heads/master@{#330247}
parent 689d919b
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendPluginRegistry.h" #include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/Sema/Sema.h"
using namespace clang; using namespace clang;
using std::string; using std::string;
...@@ -144,6 +145,23 @@ const char kClassMustDeclareGCMixinTraceMethod[] = ...@@ -144,6 +145,23 @@ const char kClassMustDeclareGCMixinTraceMethod[] =
"[blink-gc] Class %0 which inherits from GarbageCollectedMixin must" "[blink-gc] Class %0 which inherits from GarbageCollectedMixin must"
" locally declare and override trace(Visitor*)"; " locally declare and override trace(Visitor*)";
// Use a local RAV implementation to simply collect all FunctionDecls marked for
// late template parsing. This happens with the flag -fdelayed-template-parsing,
// which is on by default in MSVC-compatible mode.
std::set<FunctionDecl*> GetLateParsedFunctionDecls(TranslationUnitDecl* decl) {
struct Visitor : public RecursiveASTVisitor<Visitor> {
bool VisitFunctionDecl(FunctionDecl* function_decl) {
if (function_decl->isLateTemplateParsed())
late_parsed_decls.insert(function_decl);
return true;
}
std::set<FunctionDecl*> late_parsed_decls;
} v;
v.TraverseDecl(decl);
return v.late_parsed_decls;
}
struct BlinkGCPluginOptions { struct BlinkGCPluginOptions {
BlinkGCPluginOptions() BlinkGCPluginOptions()
: enable_oilpan(false) : enable_oilpan(false)
...@@ -1017,6 +1035,8 @@ class BlinkGCPluginConsumer : public ASTConsumer { ...@@ -1017,6 +1035,8 @@ class BlinkGCPluginConsumer : public ASTConsumer {
if (diagnostic_.hasErrorOccurred()) if (diagnostic_.hasErrorOccurred())
return; return;
ParseFunctionTemplates(context.getTranslationUnitDecl());
CollectVisitor visitor; CollectVisitor visitor;
visitor.TraverseDecl(context.getTranslationUnitDecl()); visitor.TraverseDecl(context.getTranslationUnitDecl());
...@@ -1063,6 +1083,31 @@ class BlinkGCPluginConsumer : public ASTConsumer { ...@@ -1063,6 +1083,31 @@ class BlinkGCPluginConsumer : public ASTConsumer {
} }
} }
void ParseFunctionTemplates(TranslationUnitDecl* decl) {
if (!instance_.getLangOpts().DelayedTemplateParsing)
return; // Nothing to do.
std::set<FunctionDecl*> late_parsed_decls =
GetLateParsedFunctionDecls(decl);
clang::Sema& sema = instance_.getSema();
for (const FunctionDecl* fd : late_parsed_decls) {
assert(fd->isLateTemplateParsed());
if (!Config::IsTraceMethod(fd))
continue;
if (instance_.getSourceManager().isInSystemHeader(
instance_.getSourceManager().getSpellingLoc(fd->getLocation())))
continue;
// Force parsing and AST building of the yet-uninstantiated function
// template trace method bodies.
clang::LateParsedTemplate* lpt = sema.LateParsedTemplateMap[fd];
sema.LateTemplateParser(sema.OpaqueParser, *lpt);
}
}
// Main entry for checking a record declaration. // Main entry for checking a record declaration.
void CheckRecord(RecordInfo* info) { void CheckRecord(RecordInfo* info) {
if (IsIgnored(info)) if (IsIgnored(info))
......
...@@ -214,7 +214,7 @@ class Config { ...@@ -214,7 +214,7 @@ class Config {
TRACE_AFTER_DISPATCH_IMPL_METHOD TRACE_AFTER_DISPATCH_IMPL_METHOD
}; };
static TraceMethodType GetTraceMethodType(clang::FunctionDecl* method) { static TraceMethodType GetTraceMethodType(const clang::FunctionDecl* method) {
if (method->getNumParams() != 1) if (method->getNumParams() != 1)
return NOT_TRACE_METHOD; return NOT_TRACE_METHOD;
...@@ -244,7 +244,7 @@ class Config { ...@@ -244,7 +244,7 @@ class Config {
return NOT_TRACE_METHOD; return NOT_TRACE_METHOD;
} }
static bool IsTraceMethod(clang::FunctionDecl* method) { static bool IsTraceMethod(const clang::FunctionDecl* method) {
return GetTraceMethodType(method) != NOT_TRACE_METHOD; return GetTraceMethodType(method) != NOT_TRACE_METHOD;
} }
......
#include "heap/stubs.h"
namespace blink {
struct HeapObject : public GarbageCollected<HeapObject> {
void trace(Visitor*) { }
};
template<typename T>
class TemplateBase
: public GarbageCollected<TemplateBase<T> > {
public:
void trace(Visitor* visitor) { visitor->trace(m_obj); }
private:
Member<HeapObject> m_obj;
};
class Subclass : public TemplateBase<Subclass> {
};
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment