Skip to content

Commit

Permalink
C++: fix "export" declaration wrongly marked as file-local (file: and…
Browse files Browse the repository at this point in the history
… extras:fileScope)

Close universal-ctags#4003.

Signed-off-by: Masatake YAMATO <yamato@redhat.com>
  • Loading branch information
masatake committed May 23, 2024
1 parent 300a488 commit 0805d5b
Show file tree
Hide file tree
Showing 11 changed files with 77 additions and 33 deletions.
12 changes: 6 additions & 6 deletions Units/parser-cxx.r/export-2.d/expected.tags
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
A input.cpp /^export module A; \/\/ declares the primary module interface unit for named module 'A'$/;" M properties:export
hello input.cpp /^export char const* hello() { return "hello"; }$/;" f typeref:typename:char const * properties:export
world input.cpp /^char const* world() { return "world"; }$/;" f typeref:typename:char const *
hi input.cpp /^export namespace hi$/;" n file: properties:export
hi input.cpp /^export namespace hi$/;" n properties:export
english input.cpp /^ char const* english() { return "Hi!"; }$/;" f namespace:hi typeref:typename:char const *
french input.cpp /^ char const* french() { return "Salut!"; }$/;" f namespace:hi typeref:typename:char const *
x input.cpp /^export enum x { a = 1 };$/;" g file: properties:export
a input.cpp /^export enum x { a = 1 };$/;" e enum:x file:
td input.cpp /^export typedef int td;$/;" t typeref:typename:int file: properties:export
x input.cpp /^export enum x { a = 1 };$/;" g properties:export
a input.cpp /^export enum x { a = 1 };$/;" e enum:x
td input.cpp /^export typedef int td;$/;" t typeref:typename:int properties:export
s_ input.cpp /^struct s_ {$/;" s file:
mbr input.cpp /^ int mbr;$/;" m struct:s_ typeref:typename:int file:
s input.cpp /^export struct s {$/;" s file: properties:export
mbr input.cpp /^ int mbr;$/;" m struct:s typeref:typename:int file:
s input.cpp /^export struct s {$/;" s properties:export
mbr input.cpp /^ int mbr;$/;" m struct:s typeref:typename:int
s__ input.cpp /^struct s__ {$/;" s file:
mbr input.cpp /^ int mbr;$/;" m struct:s__ typeref:typename:int file:
19 changes: 10 additions & 9 deletions Units/parser-cxx.r/export-3.d/expected.tags
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
Y input.cpp /^export module Y;$/;" M properties:export
Z0 input.cpp /^ namespace Z0 {$/;" n file: properties:export
Z0 input.cpp /^ namespace Z0 {$/;" n properties:export
z0 input.cpp /^ int z0;$/;" v namespace:Z0 typeref:typename:int
X input.cpp /^namespace X {$/;" n file:
a input.cpp /^ int a;$/;" v namespace:X typeref:typename:int
x input.cpp /^ int x;$/;" v namespace:X typeref:typename:int properties:export
f input.cpp /^ int f(int i);$/;" p namespace:X typeref:typename:int file: properties:export
u input.cpp /^ union u {$/;" u namespace:X file: properties:export
mbr input.cpp /^ int mbr;$/;" m union:X::u typeref:typename:int file:
f input.cpp /^ int f(int i);$/;" p namespace:X typeref:typename:int properties:export
u input.cpp /^ union u {$/;" u namespace:X properties:export
mbr input.cpp /^ int mbr;$/;" m union:X::u typeref:typename:int
b input.cpp /^ int b;$/;" v namespace:X typeref:typename:int
m input.cpp /^int m;$/;" v typeref:typename:int
z input.cpp /^ int z;$/;" v typeref:typename:int properties:export
E input.cpp /^ enum E { a = 1 };$/;" g file: properties:export
a input.cpp /^ enum E { a = 1 };$/;" e enum:E file:
td input.cpp /^ typedef int td;$/;" t typeref:typename:int file: properties:export
c input.cpp /^ class c {$/;" c file: properties:export
mbr input.cpp /^ int mbr;$/;" m class:c typeref:typename:int file:
E input.cpp /^ enum E { a = 1 };$/;" g properties:export
a input.cpp /^ enum E { a = 1 };$/;" e enum:E
td input.cpp /^ typedef int td;$/;" t typeref:typename:int properties:export
c input.cpp /^ class c {$/;" c properties:export
mbr input.cpp /^ int mbr;$/;" m class:c typeref:typename:int
n input.cpp /^int n;$/;" v typeref:typename:int
o input.cpp /^static int o;$/;" v typeref:typename:int file: properties:static
1 change: 1 addition & 0 deletions Units/parser-cxx.r/export-3.d/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ export {
};
}
int n;
static int o;
4 changes: 2 additions & 2 deletions Units/parser-cxx.r/export-namespace-alias.d/expected.tags
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mylib input.cpp /^export module mylib;$/;" module properties:export
X input.cpp /^export namespace X {$/;" namespace file: properties:export
X input.cpp /^export namespace X {$/;" namespace properties:export
i input.cpp /^ int i;$/;" variable namespace:X typeref:typename:int
Z input.cpp /^export namespace Z = X;$/;" alias file: properties:export name:X
Z input.cpp /^export namespace Z = X;$/;" alias properties:export name:X
8 changes: 4 additions & 4 deletions Units/parser-cxx.r/export-using.d/expected.tags
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Delta input.cpp /^export module Delta;$/;" module roles:def properties:export
Param input.cpp /^export using Param = int;$/;" typedef typeref:typename:int file: roles:def properties:export
Param input.cpp /^export using ::Param;$/;" name file: roles:def properties:export
Param input.cpp /^export using ::Param; \/\/ We can declare an object more than twice.$/;" name file: roles:def properties:export
fn input.cpp /^export void fn();$/;" prototype typeref:typename:void file: roles:def properties:export
Param input.cpp /^export using Param = int;$/;" typedef typeref:typename:int roles:def properties:export
Param input.cpp /^export using ::Param;$/;" name roles:def properties:export
Param input.cpp /^export using ::Param; \/\/ We can declare an object more than twice.$/;" name roles:def properties:export
fn input.cpp /^export void fn();$/;" prototype typeref:typename:void roles:def properties:export
28 changes: 23 additions & 5 deletions parsers/cxx/cxx_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,7 @@ bool cxxParserParseEnum(void)
int iCorkQueueIndex = CORK_NIL;
int iCorkQueueIndexFQ = CORK_NIL;

bool bEnumExported = false;
if(tag)
{
// FIXME: this is debatable
Expand All @@ -921,7 +922,13 @@ bool cxxParserParseEnum(void)
if(bIsScopedEnum)
uProperties |= CXXTagPropertyScopedEnum;
if(g_cxx.uKeywordState & CXXParserKeywordStateSeenExport)
{
uProperties |= CXXTagPropertyExport;
bEnumExported = true;
}
tag->isFileScope = (bEnumExported || cxxScopeIsExported())
? 0
: tag->isFileScope;

if(uProperties)
pszProperties = cxxTagSetProperties(uProperties);
Expand All @@ -936,7 +943,7 @@ bool cxxParserParseEnum(void)
cxxTokenDestroy(pTypeName);
}

cxxScopePush(pEnumName,CXXScopeTypeEnum,CXXScopeAccessPublic);
cxxScopePushExported(pEnumName,CXXScopeTypeEnum,CXXScopeAccessPublic, bEnumExported);
iPushedScopes++;

vString * pScopeName = cxxScopeGetFullNameAsString();
Expand Down Expand Up @@ -968,7 +975,10 @@ bool cxxParserParseEnum(void)
tag = cxxTagBegin(CXXTagKindENUMERATOR,pFirst);
if(tag)
{
tag->isFileScope = !isInputHeaderFile();
// If the enum is export'ed, we consider that its
// enumerators are not limited in a file scope.
tag->isFileScope = !isInputHeaderFile() && !cxxScopeIsExported();

cxxTagCommit(NULL);
}
}
Expand Down Expand Up @@ -1349,6 +1359,7 @@ static bool cxxParserParseClassStructOrUnionInternal(
bool bGotTemplate = g_cxx.pTemplateTokenChain &&
(g_cxx.pTemplateTokenChain->iCount > 0) &&
cxxParserCurrentLanguageIsCPP();
bool bExported = uInitialKeywordState & CXXParserKeywordStateSeenExport;

if(tag)
{
Expand Down Expand Up @@ -1400,8 +1411,14 @@ static bool cxxParserParseClassStructOrUnionInternal(
tag->isFileScope = !isInputHeaderFile();

unsigned int uProperties = 0;
if(uInitialKeywordState & CXXParserKeywordStateSeenExport)
if(bExported)
uProperties |= CXXTagPropertyExport;
// Overwrite the assigned value if the language object is export'ed
// directly or indirectly.
tag->isFileScope = (bExported || cxxScopeIsExported())
? 0
: tag->isFileScope;

vString * pszProperties = NULL;

if(uProperties)
Expand All @@ -1413,11 +1430,12 @@ static bool cxxParserParseClassStructOrUnionInternal(
vStringDelete (pszProperties); /* NULL is acceptable. */
}

cxxScopePush(
cxxScopePushExported(
pClassName,
uScopeType,
(uTagKind == CXXTagCPPKindCLASS) ?
CXXScopeAccessPrivate : CXXScopeAccessPublic
CXXScopeAccessPrivate : CXXScopeAccessPublic,
bExported
);

if(
Expand Down
7 changes: 7 additions & 0 deletions parsers/cxx/cxx_parser_function.c
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ int cxxParserMaybeParseKnRStyleFunctionDefinition(void)
pParenthesis->pChain->pTail->bFollowedBySpace = false;
}

// We don't have to consider export'ed status here; the input is written in C!
tag->isFileScope = (g_cxx.uKeywordState & CXXParserKeywordStateSeenStatic) &&
!isInputHeaderFile();

Expand All @@ -319,6 +320,7 @@ int cxxParserMaybeParseKnRStyleFunctionDefinition(void)
vStringValue(pIdentifier->pszWord)
);

// We don't have to propagate export'ed status; the input is written in C!
cxxScopePush(pIdentifier,CXXScopeTypeFunction,CXXScopeAccessUnknown);

// emit parameters
Expand Down Expand Up @@ -1626,6 +1628,11 @@ int cxxParserEmitFunctionTags(
tag->isFileScope = !isInputHeaderFile();
}
}
// Overwrite the assigned value if the language object is export'ed.
tag->isFileScope = ((g_cxx.uKeywordState & CXXParserKeywordStateSeenExport)
|| cxxScopeIsExported())
? 0
: tag->isFileScope;

vString * pszSignature = cxxTokenChainJoin(pInfo->pParenthesis->pChain,NULL,0);
if(pInfo->pSignatureConst)
Expand Down
14 changes: 9 additions & 5 deletions parsers/cxx/cxx_parser_namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,13 @@ bool cxxParserParseNamespace(void)
// namespace;

unsigned int uProperties = 0;
bool bExported = g_cxx.uKeywordState & CXXParserKeywordStateSeenExport;

if(cxxTagFieldEnabled(CXXTagFieldProperties))
{
if(g_cxx.uKeywordState & CXXParserKeywordStateSeenInline)
uProperties |= CXXTagPropertyInline;
if(g_cxx.uKeywordState & CXXParserKeywordStateSeenExport)
if(bExported)
uProperties |= CXXTagPropertyExport;
}

Expand Down Expand Up @@ -136,7 +137,7 @@ bool cxxParserParseNamespace(void)
if(tag)
{
// This is highly questionable but well.. it's how old ctags did, so we do.
tag->isFileScope = !isInputHeaderFile();
tag->isFileScope = !isInputHeaderFile() && !bExported && !cxxScopeIsExported();

vString * pszProperties = NULL;
if(uProperties)
Expand Down Expand Up @@ -249,7 +250,7 @@ bool cxxParserParseNamespace(void)
if(tag)
{
// This is highly questionable but well.. it's how old ctags did, so we do.
tag->isFileScope = !isInputHeaderFile();
tag->isFileScope = !isInputHeaderFile() && !bExported && !cxxScopeIsExported();

vString * pszProperties = uProperties ? cxxTagSetProperties(uProperties) : NULL;

Expand All @@ -269,10 +270,11 @@ bool cxxParserParseNamespace(void)

cxxTokenChainTake(g_cxx.pTokenChain,t);

cxxScopePush(
cxxScopePushExported(
t,
CXXScopeTypeNamespace,
CXXScopeAccessUnknown
CXXScopeAccessUnknown,
bExported
);

iScopeCount++;
Expand All @@ -290,6 +292,8 @@ bool cxxParserParseNamespace(void)
if(tag)
{
tag->isFileScope = !isInputHeaderFile();
// We don't have to consider "export" keyword here because an object having
// no name is not exportable.

markTagExtraBit (tag, XTAG_ANONYMOUS);

Expand Down
4 changes: 3 additions & 1 deletion parsers/cxx/cxx_parser_typedef.c
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,9 @@ void cxxParserExtractTypedef(
);
}

tag->isFileScope = !isInputHeaderFile();
tag->isFileScope = !isInputHeaderFile()
&& !(uProperties & CXXTagPropertyExport)
&& !cxxScopeIsExported();

if(bGotTemplate)
cxxTagHandleTemplateFields();
Expand Down
6 changes: 5 additions & 1 deletion parsers/cxx/cxx_parser_using.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,13 @@ bool cxxParserParseUsingClause(void)
tag->isFileScope = (cxxScopeGetType() == CXXScopeTypeNamespace) &&
(!isInputHeaderFile());

bool bExported = uInitialKeywordState & CXXParserKeywordStateSeenExport;
unsigned int uProperties = 0;
if(uInitialKeywordState & CXXParserKeywordStateSeenExport)
if(bExported)
uProperties |= CXXTagPropertyExport;
tag->isFileScope = bExported || cxxScopeIsExported()
? 0
: tag->isFileScope;
vString * pszProperties = NULL;

if(uProperties)
Expand Down
7 changes: 7 additions & 0 deletions parsers/cxx/cxx_parser_variable.c
Original file line number Diff line number Diff line change
Expand Up @@ -808,13 +808,17 @@ bool cxxParserExtractVariableDeclarations(CXXTokenChain * pChain,unsigned int uF
(
(eScopeType == CXXScopeTypeNamespace) &&
(g_cxx.uKeywordState & CXXParserKeywordStateSeenStatic) &&
(!(g_cxx.uKeywordState & CXXParserKeywordStateSeenExport)) &&
(!cxxScopeIsExported()) &&
(!isInputHeaderFile())
) ||
// locals are always hidden
(eScopeType == CXXScopeTypeFunction) ||
(
(eScopeType != CXXScopeTypeNamespace) &&
(eScopeType != CXXScopeTypeFunction) &&
(!(g_cxx.uKeywordState & CXXParserKeywordStateSeenExport)) &&
(!cxxScopeIsExported()) &&
(!isInputHeaderFile())
)
);
Expand Down Expand Up @@ -875,6 +879,9 @@ bool cxxParserExtractVariableDeclarations(CXXTokenChain * pChain,unsigned int uF
)
{
cxxScopePush(pIdentifier,CXXScopeTypeVariable,CXXScopeAccessPublic);
// We don't have to propagate the exported status to language objects
// under a variable.

cxxParserEmitTemplateParameterTags();
cxxScopePop();
} else {
Expand Down

0 comments on commit 0805d5b

Please sign in to comment.