From e141bc950a1970c6bc96fa5f55fd60c6aedbb2d0 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 24 Aug 2010 16:50:15 -0400 Subject: [PATCH] Detect unused variables --- Source/cmMakefile.cxx | 65 +++++++++++++++++++++++++++++++++++++++++-- Source/cmMakefile.h | 6 ++++ 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index d89168df0..e4973cb5b 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -44,6 +44,7 @@ class cmMakefile::Internals public: std::stack > VarStack; std::stack > VarInitStack; + std::stack > VarUsageStack; std::set VarRemoved; }; @@ -91,6 +92,8 @@ cmMakefile::cmMakefile(): Internal(new Internals) this->AddDefaultDefinitions(); this->Initialize(); this->PreOrder = false; + this->FindUnused = false; + this->DefaultToUsed = false; } cmMakefile::cmMakefile(const cmMakefile& mf): Internal(new Internals) @@ -133,6 +136,8 @@ cmMakefile::cmMakefile(const cmMakefile& mf): Internal(new Internals) this->SubDirectoryOrder = mf.SubDirectoryOrder; this->Properties = mf.Properties; this->PreOrder = mf.PreOrder; + this->FindUnused = mf.FindUnused; + this->DefaultToUsed = mf.DefaultToUsed; this->ListFileStack = mf.ListFileStack; this->Initialize(); } @@ -757,6 +762,21 @@ void cmMakefile::SetLocalGenerator(cmLocalGenerator* lg) this->AddSourceGroup("Resources", "\\.plist$"); #endif + if (this->Internal->VarUsageStack.empty()) + { + const cmDefinitions& defs = cmDefinitions(); + const std::set globalKeys = defs.LocalKeys(); + this->FindUnused = this->GetCMakeInstance()->GetFindUnused(); + this->DefaultToUsed = this->GetCMakeInstance()->GetDefaultToUsed(); + if (this->FindUnused) + { + this->Internal->VarUsageStack.push(globalKeys); + } + else + { + this->Internal->VarUsageStack.push(std::set()); + } + } } bool cmMakefile::NeedBackwardsCompatibility(unsigned int major, @@ -1690,6 +1710,10 @@ void cmMakefile::AddDefinition(const char* name, bool value) { this->Internal->VarStack.top().Set(name, value? "ON" : "OFF"); this->Internal->VarInitStack.top().insert(name); + if (this->FindUnused && this->DefaultToUsed) + { + this->Internal->VarUsageStack.top().insert(name); + } #ifdef CMAKE_BUILD_WITH_CMAKE cmVariableWatch* vv = this->GetVariableWatch(); if ( vv ) @@ -1709,6 +1733,15 @@ bool cmMakefile::VariableInitialized(const char* var) const return false; } +bool cmMakefile::VariableUsed(const char* var) const +{ + if(this->Internal->VarUsageStack.top().find(var) != this->Internal->VarUsageStack.top().end()) + { + return true; + } + return false; +} + bool cmMakefile::VariableCleared(const char* var) const { if(this->Internal->VarRemoved.find(var) != this->Internal->VarRemoved.end()) @@ -1723,6 +1756,10 @@ void cmMakefile::RemoveDefinition(const char* name) this->Internal->VarStack.top().Set(name, 0); this->Internal->VarRemoved.insert(name); this->Internal->VarInitStack.top().insert(name); + if (this->FindUnused) + { + this->Internal->VarUsageStack.top().insert(name); + } #ifdef CMAKE_BUILD_WITH_CMAKE cmVariableWatch* vv = this->GetVariableWatch(); if ( vv ) @@ -2101,6 +2138,10 @@ const char* cmMakefile::GetDefinition(const char* name) const RecordPropertyAccess(name,cmProperty::VARIABLE); } #endif + if (this->FindUnused) + { + this->Internal->VarUsageStack.top().insert(name); + } const char* def = this->Internal->VarStack.top().Get(name); if(!def) { @@ -3332,29 +3373,49 @@ void cmMakefile::PushScope() { cmDefinitions* parent = &this->Internal->VarStack.top(); const std::set& init = this->Internal->VarInitStack.top(); + const std::set& usage = this->Internal->VarUsageStack.top(); this->Internal->VarStack.push(cmDefinitions(parent)); this->Internal->VarInitStack.push(init); + this->Internal->VarUsageStack.push(usage); } void cmMakefile::PopScope() { cmDefinitions* current = &this->Internal->VarStack.top(); std::set init = this->Internal->VarInitStack.top(); + std::set usage = this->Internal->VarUsageStack.top(); const std::set& locals = current->LocalKeys(); - // Remove initialization information for variables in the local scope. + // Remove initialization and usage information for variables in the local + // scope. std::set::const_iterator it = locals.begin(); for (; it != locals.end(); ++it) { init.erase(*it); + if (this->FindUnused && usage.find(*it) == usage.end()) + { + cmOStringStream m; + m << "unused variable \'" << *it << "\'"; + this->IssueMessage(cmake::AUTHOR_WARNING, m.str()); + } + else + { + usage.erase(*it); + } } this->Internal->VarStack.pop(); this->Internal->VarInitStack.pop(); - // Push initialization up to the parent scope. + this->Internal->VarUsageStack.pop(); + // Push initialization and usage up to the parent scope. it = init.begin(); for (; it != init.end(); ++it) { this->Internal->VarInitStack.top().insert(*it); } + it = usage.begin(); + for (; it != usage.end(); ++it) + { + this->Internal->VarUsageStack.top().insert(*it); + } } void cmMakefile::RaiseScope(const char *var, const char *varDef) diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index cec273805..184253a66 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -63,6 +63,8 @@ public: /* return true if a variable has been initialized */ bool VariableInitialized(const char* ) const; + /* return true if a variable has been used */ + bool VariableUsed(const char* ) const; /* return true if a variable has been set with set(foo ) */ @@ -931,6 +933,10 @@ private: // should this makefile be processed before or after processing the parent bool PreOrder; + // Unused variable flags + bool FindUnused; + bool DefaultToUsed; + // stack of list files being read std::deque ListFileStack;