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
31e0b433
Commit
31e0b433
authored
Jun 03, 2009
by
Roberto Raggi
Browse files
Initial work on the binding pass.
parent
2ac1f797
Changes
3
Hide whitespace changes
Inline
Side-by-side
src/libs/cplusplus/CppBindings.cpp
0 → 100644
View file @
31e0b433
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Qt Software Information (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 qt-sales@nokia.com.
**
**************************************************************************/
#include
"CppBindings.h"
#include
"CppDocument.h"
#include
"Overview.h"
#include
<CoreTypes.h>
#include
<Symbols.h>
#include
<Literals.h>
#include
<Names.h>
#include
<Scope.h>
#include
<Control.h>
#include
<SymbolVisitor.h>
#include
<QtDebug>
using
namespace
CPlusPlus
;
////////////////////////////////////////////////////////////////////////////////
// Location
////////////////////////////////////////////////////////////////////////////////
Location
::
Location
()
:
_fileId
(
0
),
_sourceLocation
(
0
)
{
}
Location
::
Location
(
Symbol
*
symbol
)
:
_fileId
(
symbol
->
fileId
()),
_sourceLocation
(
symbol
->
sourceLocation
())
{
}
Location
::
Location
(
StringLiteral
*
fileId
,
unsigned
sourceLocation
)
:
_fileId
(
fileId
),
_sourceLocation
(
sourceLocation
)
{
}
////////////////////////////////////////////////////////////////////////////////
// NamespaceBinding
////////////////////////////////////////////////////////////////////////////////
NamespaceBinding
::
NamespaceBinding
(
NamespaceBinding
*
parent
)
:
parent
(
parent
),
anonymousNamespaceBinding
(
0
)
{
if
(
parent
)
parent
->
children
.
append
(
this
);
}
NamespaceBinding
::~
NamespaceBinding
()
{
qDeleteAll
(
children
);
qDeleteAll
(
classBindings
);
}
NameId
*
NamespaceBinding
::
name
()
const
{
if
(
symbols
.
size
())
{
if
(
Name
*
name
=
symbols
.
at
(
0
)
->
name
())
{
NameId
*
nameId
=
name
->
asNameId
();
Q_ASSERT
(
nameId
!=
0
);
return
nameId
;
}
}
return
0
;
}
Identifier
*
NamespaceBinding
::
identifier
()
const
{
if
(
NameId
*
nameId
=
name
())
return
nameId
->
identifier
();
return
0
;
}
NamespaceBinding
*
NamespaceBinding
::
globalNamespaceBinding
()
{
NamespaceBinding
*
it
=
this
;
for
(;
it
;
it
=
it
->
parent
)
{
if
(
!
it
->
parent
)
break
;
}
return
it
;
}
NamespaceBinding
*
NamespaceBinding
::
findNamespaceBinding
(
Name
*
name
)
{
if
(
!
name
)
return
anonymousNamespaceBinding
;
else
if
(
NameId
*
nameId
=
name
->
asNameId
())
return
findNamespaceBindingForNameId
(
nameId
);
// invalid binding
return
0
;
}
NamespaceBinding
*
NamespaceBinding
::
findNamespaceBindingForNameId
(
NameId
*
name
)
{
foreach
(
NamespaceBinding
*
binding
,
children
)
{
Name
*
bindingName
=
binding
->
name
();
if
(
!
bindingName
)
continue
;
if
(
NameId
*
bindingNameId
=
bindingName
->
asNameId
())
{
if
(
name
->
isEqualTo
(
bindingNameId
))
return
binding
;
}
}
return
0
;
}
NamespaceBinding
*
NamespaceBinding
::
findOrCreateNamespaceBinding
(
Namespace
*
symbol
)
{
if
(
NamespaceBinding
*
binding
=
findNamespaceBinding
(
symbol
->
name
()))
{
int
index
=
0
;
for
(;
index
<
binding
->
symbols
.
size
();
++
index
)
{
Namespace
*
ns
=
binding
->
symbols
.
at
(
index
);
if
(
ns
==
symbol
)
break
;
}
if
(
index
==
binding
->
symbols
.
size
())
binding
->
symbols
.
append
(
symbol
);
return
binding
;
}
NamespaceBinding
*
binding
=
new
NamespaceBinding
(
this
);
binding
->
symbols
.
append
(
symbol
);
if
(
!
symbol
->
name
())
{
Q_ASSERT
(
!
anonymousNamespaceBinding
);
anonymousNamespaceBinding
=
binding
;
}
return
binding
;
}
static
void
closure
(
const
Location
&
loc
,
NamespaceBinding
*
binding
,
Name
*
name
,
QList
<
NamespaceBinding
*>
*
bindings
)
{
if
(
bindings
->
contains
(
binding
))
return
;
bindings
->
append
(
binding
);
Q_ASSERT
(
name
->
isNameId
());
Identifier
*
id
=
name
->
asNameId
()
->
identifier
();
bool
ignoreUsingDirectives
=
false
;
foreach
(
Namespace
*
symbol
,
binding
->
symbols
)
{
Scope
*
scope
=
symbol
->
members
();
for
(
Symbol
*
symbol
=
scope
->
lookat
(
id
);
symbol
;
symbol
=
symbol
->
next
())
{
if
(
symbol
->
name
()
!=
name
||
!
symbol
->
isNamespace
())
continue
;
const
Location
l
(
symbol
);
if
(
l
.
fileId
()
==
loc
.
fileId
()
&&
l
.
sourceLocation
()
<
loc
.
sourceLocation
())
{
ignoreUsingDirectives
=
true
;
break
;
}
}
}
if
(
ignoreUsingDirectives
)
return
;
foreach
(
NamespaceBinding
*
u
,
binding
->
usings
)
closure
(
loc
,
u
,
name
,
bindings
);
}
NamespaceBinding
*
NamespaceBinding
::
resolveNamespace
(
const
Location
&
loc
,
Name
*
name
,
bool
lookAtParent
)
{
if
(
!
name
)
return
0
;
else
if
(
NameId
*
nameId
=
name
->
asNameId
())
{
QList
<
NamespaceBinding
*>
bindings
;
closure
(
loc
,
this
,
nameId
,
&
bindings
);
QList
<
NamespaceBinding
*>
results
;
foreach
(
NamespaceBinding
*
binding
,
bindings
)
{
if
(
NamespaceBinding
*
b
=
binding
->
findNamespaceBinding
(
nameId
))
results
.
append
(
b
);
}
if
(
results
.
size
()
==
1
)
return
results
.
at
(
0
);
else
if
(
results
.
size
()
>
1
)
{
// ### FIXME: return 0;
return
results
.
at
(
0
);
}
else
if
(
parent
&&
lookAtParent
)
return
parent
->
resolveNamespace
(
loc
,
name
);
}
else
if
(
QualifiedNameId
*
q
=
name
->
asQualifiedNameId
())
{
if
(
q
->
nameCount
()
==
1
)
{
Q_ASSERT
(
q
->
isGlobal
());
return
globalNamespaceBinding
()
->
resolveNamespace
(
loc
,
q
->
nameAt
(
0
));
}
NamespaceBinding
*
current
=
this
;
if
(
q
->
isGlobal
())
current
=
globalNamespaceBinding
();
current
=
current
->
resolveNamespace
(
loc
,
q
->
nameAt
(
0
));
for
(
unsigned
i
=
1
;
current
&&
i
<
q
->
nameCount
();
++
i
)
current
=
current
->
resolveNamespace
(
loc
,
q
->
nameAt
(
i
),
false
);
return
current
;
}
return
0
;
}
// ### rewrite me
QByteArray
NamespaceBinding
::
qualifiedId
()
const
{
if
(
!
parent
)
return
"<root>"
;
QByteArray
s
;
s
.
append
(
parent
->
qualifiedId
());
s
.
append
(
"::"
);
if
(
Identifier
*
id
=
identifier
())
s
.
append
(
id
->
chars
(),
id
->
size
());
else
s
.
append
(
"<anonymous>"
);
return
s
;
}
// ### rewrite me
QByteArray
ClassBinding
::
qualifiedId
()
const
{
QByteArray
s
=
parent
->
qualifiedId
();
s
+=
"::"
;
if
(
Identifier
*
id
=
identifier
())
s
.
append
(
id
->
chars
(),
id
->
size
());
else
s
.
append
(
"<anonymous>"
);
return
s
;
}
static
int
depth
;
void
NamespaceBinding
::
dump
()
{
qDebug
()
<<
QByteArray
(
depth
,
' '
).
constData
()
<<
"namespace"
<<
qualifiedId
().
constData
()
<<
" # "
<<
symbols
.
size
();
++
depth
;
foreach
(
ClassBinding
*
classBinding
,
classBindings
)
{
classBinding
->
dump
();
}
foreach
(
NamespaceBinding
*
child
,
children
)
{
child
->
dump
();
}
--
depth
;
}
void
ClassBinding
::
dump
()
{
qDebug
()
<<
QByteArray
(
depth
,
' '
).
constData
()
<<
"class"
<<
qualifiedId
().
constData
()
<<
" # "
<<
symbols
.
size
();
++
depth
;
foreach
(
ClassBinding
*
classBinding
,
children
)
{
classBinding
->
dump
();
}
--
depth
;
}
////////////////////////////////////////////////////////////////////////////////
// ClassBinding
////////////////////////////////////////////////////////////////////////////////
ClassBinding
::
ClassBinding
(
NamespaceBinding
*
parent
)
:
parent
(
parent
)
{
parent
->
classBindings
.
append
(
this
);
}
ClassBinding
::
ClassBinding
(
ClassBinding
*
parentClass
)
{
parent
=
parentClass
->
parent
;
parentClass
->
children
.
append
(
this
);
}
ClassBinding
::~
ClassBinding
()
{
qDeleteAll
(
children
);
}
NameId
*
ClassBinding
::
name
()
const
{
if
(
symbols
.
size
())
{
if
(
Name
*
name
=
symbols
.
at
(
0
)
->
name
())
{
NameId
*
nameId
=
name
->
asNameId
();
return
nameId
;
}
}
return
0
;
}
Identifier
*
ClassBinding
::
identifier
()
const
{
if
(
NameId
*
nameId
=
name
())
return
nameId
->
identifier
();
return
0
;
}
namespace
{
////////////////////////////////////////////////////////////////////////////////
// Binder
////////////////////////////////////////////////////////////////////////////////
class
Binder
:
protected
SymbolVisitor
{
public:
Binder
(
NamespaceBinding
*
globals
);
virtual
~
Binder
();
NamespaceBinding
*
operator
()(
Document
::
Ptr
doc
,
const
Snapshot
&
snapshot
)
{
namespaceBinding
=
_globals
;
const
Snapshot
previousSnapshot
=
_snapshot
;
_snapshot
=
snapshot
;
(
void
)
bind
(
doc
);
_snapshot
=
previousSnapshot
;
return
_globals
;
}
Snapshot
_snapshot
;
protected:
NamespaceBinding
*
bind
(
Document
::
Ptr
doc
)
{
QSet
<
QString
>
processed
;
return
bind
(
doc
,
&
processed
);
}
NamespaceBinding
*
bind
(
Document
::
Ptr
doc
,
QSet
<
QString
>
*
processed
)
{
if
(
processed
->
contains
(
doc
->
fileName
()))
return
0
;
processed
->
insert
(
doc
->
fileName
());
foreach
(
const
Document
::
Include
&
i
,
doc
->
includes
())
{
if
(
Document
::
Ptr
includedDoc
=
_snapshot
.
value
(
i
.
fileName
()))
{
/*NamepaceBinding *binding = */
bind
(
includedDoc
,
processed
);
}
}
Namespace
*
ns
=
doc
->
globalNamespace
();
_globals
->
symbols
.
append
(
ns
);
for
(
unsigned
i
=
0
;
i
<
ns
->
memberCount
();
++
i
)
{
(
void
)
bind
(
ns
->
memberAt
(
i
),
_globals
);
}
return
_globals
;
}
NamespaceBinding
*
bind
(
Symbol
*
symbol
,
NamespaceBinding
*
binding
);
NamespaceBinding
*
findOrCreateNamespaceBinding
(
Namespace
*
symbol
);
NamespaceBinding
*
resolveNamespace
(
const
Location
&
loc
,
Name
*
name
);
NamespaceBinding
*
switchNamespaceBinding
(
NamespaceBinding
*
binding
);
ClassBinding
*
findOrCreateClassBinding
(
Class
*
classSymbol
);
ClassBinding
*
findClassBinding
(
Name
*
name
);
ClassBinding
*
switchClassBinding
(
ClassBinding
*
binding
);
using
SymbolVisitor
::
visit
;
virtual
bool
visit
(
Namespace
*
);
virtual
bool
visit
(
UsingNamespaceDirective
*
);
virtual
bool
visit
(
Class
*
);
virtual
bool
visit
(
Function
*
);
virtual
bool
visit
(
Block
*
);
private:
NamespaceBinding
*
_globals
;
NamespaceBinding
*
namespaceBinding
;
ClassBinding
*
classBinding
;
};
Binder
::
Binder
(
NamespaceBinding
*
globals
)
:
_globals
(
globals
),
namespaceBinding
(
0
),
classBinding
(
0
)
{
}
Binder
::~
Binder
()
{
}
NamespaceBinding
*
Binder
::
bind
(
Symbol
*
symbol
,
NamespaceBinding
*
binding
)
{
NamespaceBinding
*
previousBinding
=
switchNamespaceBinding
(
binding
);
accept
(
symbol
);
return
switchNamespaceBinding
(
previousBinding
);
}
NamespaceBinding
*
Binder
::
findOrCreateNamespaceBinding
(
Namespace
*
symbol
)
{
return
namespaceBinding
->
findOrCreateNamespaceBinding
(
symbol
);
}
NamespaceBinding
*
Binder
::
resolveNamespace
(
const
Location
&
loc
,
Name
*
name
)
{
if
(
!
namespaceBinding
)
return
0
;
return
namespaceBinding
->
resolveNamespace
(
loc
,
name
);
}
NamespaceBinding
*
Binder
::
switchNamespaceBinding
(
NamespaceBinding
*
binding
)
{
NamespaceBinding
*
previousBinding
=
namespaceBinding
;
namespaceBinding
=
binding
;
return
previousBinding
;
}
ClassBinding
*
Binder
::
findOrCreateClassBinding
(
Class
*
classSymbol
)
{
ClassBinding
*
binding
=
0
;
if
(
classBinding
)
binding
=
new
ClassBinding
(
classBinding
);
else
binding
=
new
ClassBinding
(
namespaceBinding
);
binding
->
symbols
.
append
(
classSymbol
);
return
binding
;
}
ClassBinding
*
Binder
::
findClassBinding
(
Name
*
name
)
{
qDebug
()
<<
Q_FUNC_INFO
;
return
0
;
}
ClassBinding
*
Binder
::
switchClassBinding
(
ClassBinding
*
binding
)
{
ClassBinding
*
previousClassBinding
=
classBinding
;
classBinding
=
binding
;
return
previousClassBinding
;
}
bool
Binder
::
visit
(
Namespace
*
symbol
)
{
NamespaceBinding
*
binding
=
findOrCreateNamespaceBinding
(
symbol
);
for
(
unsigned
i
=
0
;
i
<
symbol
->
memberCount
();
++
i
)
{
Symbol
*
member
=
symbol
->
memberAt
(
i
);
bind
(
member
,
binding
);
}
return
false
;
}
bool
Binder
::
visit
(
UsingNamespaceDirective
*
u
)
{
NamespaceBinding
*
resolved
=
resolveNamespace
(
Location
(
u
),
u
->
name
());
if
(
!
resolved
)
return
false
;
namespaceBinding
->
usings
.
append
(
resolved
);
return
false
;
}
bool
Binder
::
visit
(
Class
*
classSymbol
)
{
Overview
oo
;
ClassBinding
*
binding
=
findOrCreateClassBinding
(
classSymbol
);
ClassBinding
*
previousClassBinding
=
switchClassBinding
(
binding
);
#if 0
for (unsigned i = 0; i < classSymbol->baseClassCount(); ++i) {
BaseClass *baseClass = classSymbol->baseClassAt(i);
ClassBinding *baseClassBinding = findClassBinding(baseClass->name());
// ### wrong
binding->baseClassBindings.append(baseClassBinding);
}
#endif
for
(
unsigned
i
=
0
;
i
<
classSymbol
->
memberCount
();
++
i
)
accept
(
classSymbol
->
memberAt
(
i
));
(
void
)
switchClassBinding
(
previousClassBinding
);
return
false
;
}
bool
Binder
::
visit
(
Function
*
)
{
return
false
;
}
bool
Binder
::
visit
(
Block
*
)
{
return
false
;
}
}
// end of anonymous namespace
src/libs/cplusplus/CppBindings.h
0 → 100644
View file @
31e0b433
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Qt Software Information (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 qt-sales@nokia.com.
**
**************************************************************************/
#ifndef CPPBINDINGS_H
#define CPPBINDINGS_H
#include
<CPlusPlusForwardDeclarations.h>
#include
<QtCore/QList>
#include
<QtCore/QSharedPointer>
#include
<QtCore/QString>
#include
<QtCore/QByteArray>
namespace
CPlusPlus
{
class
Location
;
class
Binding
;
class
NamespaceBinding
;
class
ClassBinding
;
typedef
QSharedPointer
<
Binding
>
BindingPtr
;
typedef
QSharedPointer
<
ClassBinding
>
ClassBindingPtr
;