Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Marco Bubke
flatpak-qt-creator
Commits
9b24e0ae
Commit
9b24e0ae
authored
Jul 15, 2010
by
Roberto Raggi
Browse files
Highlight local and member symbols.
parent
cc3179ef
Changes
7
Hide whitespace changes
Inline
Side-by-side
src/plugins/cppeditor/cppchecksymbols.cpp
View file @
9b24e0ae
...
...
@@ -28,6 +28,8 @@
**************************************************************************/
#include
"cppchecksymbols.h"
#include
"cpplocalsymbols.h"
#include
<cplusplus/Overview.h>
#include
<Names.h>
...
...
@@ -45,6 +47,7 @@
#include
<qtconcurrent/runextensions.h>
using
namespace
CPlusPlus
;
using
namespace
CppEditor
::
Internal
;
namespace
{
...
...
@@ -53,6 +56,7 @@ class CollectTypes: protected SymbolVisitor
Document
::
Ptr
_doc
;
Snapshot
_snapshot
;
QSet
<
QByteArray
>
_types
;
QSet
<
QByteArray
>
_members
;
QList
<
ScopedSymbol
*>
_scopes
;
QList
<
NameAST
*>
_names
;
bool
_mainDocument
;
...
...
@@ -70,6 +74,11 @@ public:
return
_types
;
}
const
QSet
<
QByteArray
>
&
members
()
const
{
return
_members
;
}
const
QList
<
ScopedSymbol
*>
&
scopes
()
const
{
return
_scopes
;
...
...
@@ -126,6 +135,18 @@ protected:
}
}
void
addMember
(
const
Name
*
name
)
{
if
(
!
name
)
{
return
;
}
else
if
(
name
->
isNameId
())
{
const
Identifier
*
id
=
name
->
identifier
();
_members
.
insert
(
QByteArray
::
fromRawData
(
id
->
chars
(),
id
->
size
()));
}
}
void
addScope
(
ScopedSymbol
*
symbol
)
{
if
(
_mainDocument
)
...
...
@@ -166,6 +187,8 @@ protected:
{
if
(
symbol
->
isTypedef
())
addType
(
symbol
->
name
());
else
if
(
!
symbol
->
type
()
->
isFunctionType
()
&&
symbol
->
enclosingSymbol
()
->
isClass
())
addMember
(
symbol
->
name
());
return
true
;
}
...
...
@@ -267,6 +290,7 @@ CheckSymbols::CheckSymbols(Document::Ptr doc, const LookupContext &context)
_fileName
=
doc
->
fileName
();
CollectTypes
collectTypes
(
doc
,
context
.
snapshot
());
_potentialTypes
=
collectTypes
.
types
();
_potentialMembers
=
collectTypes
.
members
();
_scopes
=
collectTypes
.
scopes
();
_flushRequested
=
false
;
_flushLine
=
0
;
...
...
@@ -351,6 +375,12 @@ bool CheckSymbols::visit(NamedTypeSpecifierAST *)
return
true
;
}
bool
CheckSymbols
::
visit
(
MemberAccessAST
*
ast
)
{
accept
(
ast
->
base_expression
);
return
false
;
}
void
CheckSymbols
::
checkNamespace
(
NameAST
*
name
)
{
if
(
!
name
)
...
...
@@ -380,6 +410,28 @@ void CheckSymbols::checkName(NameAST *ast)
Scope
*
scope
=
findScope
(
ast
);
const
QList
<
Symbol
*>
candidates
=
_context
.
lookup
(
ast
->
name
,
scope
);
addTypeUsage
(
candidates
,
ast
);
}
else
if
(
_potentialMembers
.
contains
(
id
))
{
Scope
*
scope
=
findScope
(
ast
);
const
QList
<
Symbol
*>
candidates
=
_context
.
lookup
(
ast
->
name
,
scope
);
addMemberUsage
(
candidates
,
ast
);
}
}
}
}
void
CheckSymbols
::
checkMemberName
(
NameAST
*
ast
)
{
if
(
ast
&&
ast
->
name
)
{
if
(
const
Identifier
*
ident
=
ast
->
name
->
identifier
())
{
const
QByteArray
id
=
QByteArray
::
fromRawData
(
ident
->
chars
(),
ident
->
size
());
if
(
_potentialMembers
.
contains
(
id
))
{
Scope
*
scope
=
findScope
(
ast
);
const
QList
<
Symbol
*>
candidates
=
_context
.
lookup
(
ast
->
name
,
scope
);
addMemberUsage
(
candidates
,
ast
);
}
else
if
(
_potentialMembers
.
contains
(
id
))
{
Scope
*
scope
=
findScope
(
ast
);
const
QList
<
Symbol
*>
candidates
=
_context
.
lookup
(
ast
->
name
,
scope
);
addMemberUsage
(
candidates
,
ast
);
}
}
}
...
...
@@ -473,14 +525,35 @@ void CheckSymbols::endVisit(TemplateDeclarationAST *)
_templateDeclarationStack
.
takeFirst
();
}
bool
CheckSymbols
::
visit
(
FunctionDefinitionAST
*
ast
)
{
_functionDefinitionStack
.
append
(
ast
);
const
LocalSymbols
locals
(
_doc
,
ast
);
QList
<
SemanticInfo
::
Use
>
uses
;
foreach
(
uses
,
locals
.
uses
)
{
foreach
(
const
SemanticInfo
::
Use
&
u
,
uses
)
addTypeUsage
(
u
);
}
accept
(
ast
->
decl_specifier_list
);
accept
(
ast
->
declarator
);
accept
(
ast
->
ctor_initializer
);
accept
(
ast
->
function_body
);
_functionDefinitionStack
.
removeLast
();
return
false
;
}
void
CheckSymbols
::
addTypeUsage
(
const
Use
&
use
)
{
if
(
_typeUsages
.
size
()
>=
50
)
{
if
(
_flushRequested
&&
use
.
line
!=
_flushLine
)
flush
();
else
if
(
!
_flushRequested
)
{
_flushRequested
=
true
;
_flushLine
=
use
.
line
;
if
(
_functionDefinitionStack
.
isEmpty
())
{
if
(
_typeUsages
.
size
()
>=
50
)
{
if
(
_flushRequested
&&
use
.
line
!=
_flushLine
)
flush
();
else
if
(
!
_flushRequested
)
{
_flushRequested
=
true
;
_flushLine
=
use
.
line
;
}
}
}
...
...
@@ -538,6 +611,36 @@ void CheckSymbols::addTypeUsage(const QList<Symbol *> &candidates, NameAST *ast)
}
}
void
CheckSymbols
::
addMemberUsage
(
const
QList
<
Symbol
*>
&
candidates
,
NameAST
*
ast
)
{
unsigned
startToken
=
ast
->
firstToken
();
if
(
DestructorNameAST
*
dtor
=
ast
->
asDestructorName
())
startToken
=
dtor
->
identifier_token
;
const
Token
&
tok
=
tokenAt
(
startToken
);
if
(
tok
.
generated
())
return
;
unsigned
line
,
column
;
getTokenStartPosition
(
startToken
,
&
line
,
&
column
);
const
unsigned
length
=
tok
.
length
();
foreach
(
Symbol
*
c
,
candidates
)
{
if
(
!
c
->
isDeclaration
())
continue
;
else
if
(
c
->
isTypedef
())
continue
;
else
if
(
c
->
type
()
->
isFunctionType
())
continue
;
else
if
(
!
c
->
enclosingSymbol
()
->
isClass
())
continue
;
const
Use
use
(
line
,
column
,
length
,
Use
::
Field
);
addTypeUsage
(
use
);
//qDebug() << "added use" << oo(ast->name) << line << column << length;
}
}
unsigned
CheckSymbols
::
startOfTemplateDeclaration
(
TemplateDeclarationAST
*
ast
)
const
{
if
(
ast
->
declaration
)
{
...
...
src/plugins/cppeditor/cppchecksymbols.h
View file @
9b24e0ae
...
...
@@ -87,6 +87,9 @@ protected:
void
addTypeUsage
(
const
QList
<
Symbol
*>
&
candidates
,
NameAST
*
ast
);
void
addTypeUsage
(
const
Use
&
use
);
void
checkMemberName
(
NameAST
*
ast
);
void
addMemberUsage
(
const
QList
<
Symbol
*>
&
candidates
,
NameAST
*
ast
);
virtual
bool
preVisit
(
AST
*
);
virtual
bool
visit
(
NamespaceAST
*
);
...
...
@@ -105,6 +108,9 @@ protected:
virtual
bool
visit
(
TypenameTypeParameterAST
*
ast
);
virtual
bool
visit
(
TemplateTypeParameterAST
*
ast
);
virtual
bool
visit
(
FunctionDefinitionAST
*
ast
);
virtual
bool
visit
(
MemberAccessAST
*
ast
);
unsigned
startOfTemplateDeclaration
(
TemplateDeclarationAST
*
ast
)
const
;
Scope
*
findScope
(
AST
*
ast
)
const
;
...
...
@@ -116,8 +122,10 @@ private:
QString
_fileName
;
QList
<
Document
::
DiagnosticMessage
>
_diagnosticMessages
;
QSet
<
QByteArray
>
_potentialTypes
;
QSet
<
QByteArray
>
_potentialMembers
;
QList
<
ScopedSymbol
*>
_scopes
;
QList
<
TemplateDeclarationAST
*>
_templateDeclarationStack
;
QList
<
FunctionDefinitionAST
*>
_functionDefinitionStack
;
QVector
<
Use
>
_typeUsages
;
bool
_flushRequested
;
unsigned
_flushLine
;
...
...
src/plugins/cppeditor/cppeditor.cpp
View file @
9b24e0ae
...
...
@@ -33,6 +33,7 @@
#include
"cpphighlighter.h"
#include
"cppchecksymbols.h"
#include
"cppquickfix.h"
#include
"cpplocalsymbols.h"
#include
<AST.h>
#include
<Control.h>
...
...
@@ -172,240 +173,6 @@ private:
CPlusPlus
::
OverviewModel
*
m_sourceModel
;
};
class
FindLocalUses
:
protected
ASTVisitor
{
Scope
*
_functionScope
;
Document
::
Ptr
_doc
;
public:
FindLocalUses
(
Document
::
Ptr
doc
)
:
ASTVisitor
(
doc
->
translationUnit
()),
_doc
(
doc
),
hasD
(
false
),
hasQ
(
false
)
{
}
// local and external uses.
SemanticInfo
::
LocalUseMap
localUses
;
bool
hasD
;
bool
hasQ
;
void
operator
()(
DeclarationAST
*
ast
)
{
localUses
.
clear
();
if
(
!
ast
)
return
;
if
(
FunctionDefinitionAST
*
def
=
ast
->
asFunctionDefinition
())
{
if
(
def
->
symbol
)
{
_functionScope
=
def
->
symbol
->
members
();
accept
(
ast
);
}
}
else
if
(
ObjCMethodDeclarationAST
*
decl
=
ast
->
asObjCMethodDeclaration
())
{
if
(
decl
->
method_prototype
->
symbol
)
{
_functionScope
=
decl
->
method_prototype
->
symbol
->
members
();
accept
(
ast
);
}
}
}
protected:
using
ASTVisitor
::
visit
;
bool
findMember
(
Scope
*
scope
,
NameAST
*
ast
,
unsigned
line
,
unsigned
column
)
{
if
(
!
(
ast
&&
ast
->
name
))
return
false
;
const
Identifier
*
id
=
ast
->
name
->
identifier
();
if
(
scope
)
{
for
(
Symbol
*
member
=
scope
->
lookat
(
id
);
member
;
member
=
member
->
next
())
{
if
(
member
->
identifier
()
!=
id
)
continue
;
else
if
(
member
->
line
()
<
line
||
(
member
->
line
()
==
line
&&
member
->
column
()
<=
column
))
{
localUses
[
member
].
append
(
SemanticInfo
::
Use
(
line
,
column
,
id
->
size
()));
return
true
;
}
}
}
return
false
;
}
void
searchUsesInTemplateArguments
(
NameAST
*
name
)
{
if
(
!
name
)
return
;
else
if
(
TemplateIdAST
*
template_id
=
name
->
asTemplateId
())
{
for
(
TemplateArgumentListAST
*
it
=
template_id
->
template_argument_list
;
it
;
it
=
it
->
next
)
{
accept
(
it
->
value
);
}
}
}
virtual
bool
visit
(
SimpleNameAST
*
ast
)
{
return
findMemberForToken
(
ast
->
firstToken
(),
ast
);
}
bool
findMemberForToken
(
unsigned
tokenIdx
,
NameAST
*
ast
)
{
const
Token
&
tok
=
tokenAt
(
tokenIdx
);
if
(
tok
.
generated
())
return
false
;
unsigned
line
,
column
;
getTokenStartPosition
(
tokenIdx
,
&
line
,
&
column
);
Scope
*
scope
=
_doc
->
scopeAt
(
line
,
column
);
while
(
scope
)
{
if
(
scope
->
isFunctionScope
())
{
Function
*
fun
=
scope
->
owner
()
->
asFunction
();
if
(
findMember
(
fun
->
members
(),
ast
,
line
,
column
))
return
false
;
else
if
(
findMember
(
fun
->
arguments
(),
ast
,
line
,
column
))
return
false
;
}
else
if
(
scope
->
isObjCMethodScope
())
{
ObjCMethod
*
method
=
scope
->
owner
()
->
asObjCMethod
();
if
(
findMember
(
method
->
members
(),
ast
,
line
,
column
))
return
false
;
else
if
(
findMember
(
method
->
arguments
(),
ast
,
line
,
column
))
return
false
;
}
else
if
(
scope
->
isBlockScope
())
{
if
(
findMember
(
scope
,
ast
,
line
,
column
))
return
false
;
}
else
{
break
;
}
scope
=
scope
->
enclosingScope
();
}
return
false
;
}
virtual
bool
visit
(
TemplateIdAST
*
ast
)
{
for
(
TemplateArgumentListAST
*
arg
=
ast
->
template_argument_list
;
arg
;
arg
=
arg
->
next
)
accept
(
arg
->
value
);
const
Token
&
tok
=
tokenAt
(
ast
->
identifier_token
);
if
(
tok
.
generated
())
return
false
;
unsigned
line
,
column
;
getTokenStartPosition
(
ast
->
firstToken
(),
&
line
,
&
column
);
Scope
*
scope
=
_doc
->
scopeAt
(
line
,
column
);
while
(
scope
)
{
if
(
scope
->
isFunctionScope
())
{
Function
*
fun
=
scope
->
owner
()
->
asFunction
();
if
(
findMember
(
fun
->
members
(),
ast
,
line
,
column
))
return
false
;
else
if
(
findMember
(
fun
->
arguments
(),
ast
,
line
,
column
))
return
false
;
}
else
if
(
scope
->
isBlockScope
())
{
if
(
findMember
(
scope
,
ast
,
line
,
column
))
return
false
;
}
else
{
break
;
}
scope
=
scope
->
enclosingScope
();
}
return
false
;
}
virtual
bool
visit
(
QualifiedNameAST
*
ast
)
{
for
(
NestedNameSpecifierListAST
*
it
=
ast
->
nested_name_specifier_list
;
it
;
it
=
it
->
next
)
searchUsesInTemplateArguments
(
it
->
value
->
class_or_namespace_name
);
searchUsesInTemplateArguments
(
ast
->
unqualified_name
);
return
false
;
}
virtual
bool
visit
(
MemberAccessAST
*
ast
)
{
// accept only the base expression
accept
(
ast
->
base_expression
);
// and ignore the member name.
return
false
;
}
virtual
bool
visit
(
ElaboratedTypeSpecifierAST
*
)
{
// ### template args
return
false
;
}
virtual
bool
visit
(
ClassSpecifierAST
*
)
{
// ### template args
return
false
;
}
virtual
bool
visit
(
EnumSpecifierAST
*
)
{
// ### template args
return
false
;
}
virtual
bool
visit
(
UsingDirectiveAST
*
)
{
return
false
;
}
virtual
bool
visit
(
UsingAST
*
ast
)
{
accept
(
ast
->
name
);
return
false
;
}
virtual
bool
visit
(
QtMemberDeclarationAST
*
ast
)
{
if
(
tokenKind
(
ast
->
q_token
)
==
T_Q_D
)
hasD
=
true
;
else
hasQ
=
true
;
return
true
;
}
virtual
bool
visit
(
ExpressionOrDeclarationStatementAST
*
ast
)
{
accept
(
ast
->
declaration
);
return
false
;
}
virtual
bool
visit
(
FunctionDeclaratorAST
*
ast
)
{
accept
(
ast
->
parameters
);
for
(
SpecifierListAST
*
it
=
ast
->
cv_qualifier_list
;
it
;
it
=
it
->
next
)
accept
(
it
->
value
);
accept
(
ast
->
exception_specification
);
return
false
;
}
virtual
bool
visit
(
ObjCMethodPrototypeAST
*
ast
)
{
accept
(
ast
->
argument_list
);
return
false
;
}
virtual
bool
visit
(
ObjCMessageArgumentDeclarationAST
*
ast
)
{
accept
(
ast
->
param_name
);
return
false
;
}
};
class
FunctionDefinitionUnderCursor
:
protected
ASTVisitor
{
unsigned
_line
;
...
...
@@ -1131,6 +898,12 @@ void CPPEditor::highlightTypeUsages(int from, int to)
Q_ASSERT
(
!
chunks
.
isEmpty
());
QTextBlock
b
=
doc
->
findBlockByNumber
(
m_nextHighlightBlockNumber
);
QTextCharFormat
localUseFormat
;
localUseFormat
.
setForeground
(
Qt
::
darkBlue
);
// ### hardcoded
QTextCharFormat
memberUseFormat
;
memberUseFormat
.
setForeground
(
Qt
::
darkRed
);
// ### hardcoded
QMapIterator
<
int
,
QVector
<
SemanticInfo
::
Use
>
>
it
(
chunks
);
while
(
b
.
isValid
()
&&
it
.
hasNext
())
{
it
.
next
();
...
...
@@ -1146,7 +919,24 @@ void CPPEditor::highlightTypeUsages(int from, int to)
QList
<
QTextLayout
::
FormatRange
>
formats
;
foreach
(
const
SemanticInfo
::
Use
&
use
,
it
.
value
())
{
QTextLayout
::
FormatRange
formatRange
;
formatRange
.
format
=
m_typeFormat
;
switch
(
use
.
kind
)
{
case
SemanticInfo
::
Use
::
Type
:
formatRange
.
format
=
m_typeFormat
;
break
;
case
SemanticInfo
::
Use
::
Field
:
formatRange
.
format
=
memberUseFormat
;
break
;
case
SemanticInfo
::
Use
::
Local
:
formatRange
.
format
=
localUseFormat
;
break
;
default:
continue
;
}
formatRange
.
start
=
use
.
column
-
1
;
formatRange
.
length
=
use
.
length
;
formats
.
append
(
formatRange
);
...
...
@@ -2187,8 +1977,7 @@ SemanticInfo SemanticHighlighter::semanticInfo(const Source &source)
Snapshot
snapshot
;
Document
::
Ptr
doc
;
QList
<
Document
::
DiagnosticMessage
>
diagnosticMessages
;
QList
<
SemanticInfo
::
Use
>
typeUsages
,
objcKeywords
;
LookupContext
context
;
QList
<
SemanticInfo
::
Use
>
objcKeywords
;
if
(
!
source
.
force
&&
revision
==
source
.
revision
)
{
m_mutex
.
lock
();
...
...
@@ -2207,13 +1996,7 @@ SemanticInfo SemanticHighlighter::semanticInfo(const Source &source)
doc
->
check
();
#if 0
context = LookupContext(doc, snapshot);
if (TranslationUnit *unit = doc->translationUnit()) {
CheckUndefinedSymbols checkUndefinedSymbols(unit, context);
diagnosticMessages = checkUndefinedSymbols(unit->ast());
typeUsages = checkUndefinedSymbols.typeUsages();
FindObjCKeywords findObjCKeywords(unit); // ### remove me
objcKeywords = findObjCKeywords();
}
...
...
@@ -2226,14 +2009,13 @@ SemanticInfo SemanticHighlighter::semanticInfo(const Source &source)
FunctionDefinitionUnderCursor
functionDefinitionUnderCursor
(
translationUnit
);
DeclarationAST
*
currentFunctionDefinition
=
functionDefinitionUnderCursor
(
ast
,
source
.
line
,
source
.
column
);
FindLocalUses
useTable
(
doc
);
useTable
(
currentFunctionDefinition
);
const
LocalSymbols
useTable
(
doc
,
currentFunctionDefinition
);
SemanticInfo
semanticInfo
;
semanticInfo
.
revision
=
source
.
revision
;
semanticInfo
.
snapshot
=
snapshot
;
semanticInfo
.
doc
=
doc
;
semanticInfo
.
localUses
=
useTable
.
localU
ses
;
semanticInfo
.
localUses
=
useTable
.
u
ses
;
semanticInfo
.
hasQ
=
useTable
.
hasQ
;
semanticInfo
.
hasD
=
useTable
.
hasD
;
semanticInfo
.
forced
=
source
.
force
;
...
...
src/plugins/cppeditor/cppeditor.pro
View file @
9b24e0ae
...
...
@@ -20,7 +20,8 @@ HEADERS += cppplugin.h \
cppchecksymbols
.
h
\
cppsemanticinfo
.
h
\
cppoutline
.
h
\
cppdeclfromdef
.
h
cppdeclfromdef
.
h
\
cpplocalsymbols
.
h
SOURCES
+=
cppplugin
.
cpp
\
cppeditor
.
cpp
\
...
...
@@ -33,7 +34,8 @@ SOURCES += cppplugin.cpp \
cppchecksymbols
.
cpp
\
cppsemanticinfo
.
cpp
\
cppoutline
.
cpp
\
cppdeclfromdef
.
cpp
cppdeclfromdef
.
cpp
\
cpplocalsymbols
.
cpp
RESOURCES
+=
cppeditor
.
qrc
...
...
src/plugins/cppeditor/cpplocalsymbols.cpp
0 → 100644
View file @
9b24e0ae
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#include
"cpplocalsymbols.h"
#include
"cppsemanticinfo.h"
#include
<cplusplus/CppDocument.h>
#include
<ASTVisitor.h>
#include
<AST.h>
#include
<Scope.h>
#include
<Symbols.h>
#include
<CoreTypes.h>
#include
<Names.h>
#include
<Literals.h>
using
namespace
CPlusPlus
;