Coverage Report

Created: 2020-09-19 12:23

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/AST/TemplateBase.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- TemplateBase.cpp - Common template AST class implementation --------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This file implements common classes used throughout C++ template
10
// representations.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#include "clang/AST/TemplateBase.h"
15
#include "clang/AST/ASTContext.h"
16
#include "clang/AST/Decl.h"
17
#include "clang/AST/DeclBase.h"
18
#include "clang/AST/DeclTemplate.h"
19
#include "clang/AST/DependenceFlags.h"
20
#include "clang/AST/Expr.h"
21
#include "clang/AST/ExprCXX.h"
22
#include "clang/AST/PrettyPrinter.h"
23
#include "clang/AST/TemplateName.h"
24
#include "clang/AST/Type.h"
25
#include "clang/AST/TypeLoc.h"
26
#include "clang/Basic/Diagnostic.h"
27
#include "clang/Basic/LLVM.h"
28
#include "clang/Basic/LangOptions.h"
29
#include "clang/Basic/SourceLocation.h"
30
#include "llvm/ADT/APSInt.h"
31
#include "llvm/ADT/FoldingSet.h"
32
#include "llvm/ADT/None.h"
33
#include "llvm/ADT/SmallString.h"
34
#include "llvm/ADT/StringRef.h"
35
#include "llvm/Support/Casting.h"
36
#include "llvm/Support/Compiler.h"
37
#include "llvm/Support/ErrorHandling.h"
38
#include "llvm/Support/raw_ostream.h"
39
#include <cassert>
40
#include <cstddef>
41
#include <cstdint>
42
#include <cstring>
43
44
using namespace clang;
45
46
/// Print a template integral argument value.
47
///
48
/// \param TemplArg the TemplateArgument instance to print.
49
///
50
/// \param Out the raw_ostream instance to use for printing.
51
///
52
/// \param Policy the printing policy for EnumConstantDecl printing.
53
static void printIntegral(const TemplateArgument &TemplArg,
54
197k
                          raw_ostream &Out, const PrintingPolicy& Policy) {
55
197k
  const Type *T = TemplArg.getIntegralType().getTypePtr();
56
197k
  const llvm::APSInt &Val = TemplArg.getAsIntegral();
57
197k
58
197k
  if (const EnumType *ET = T->getAs<EnumType>()) {
59
1.26k
    for (const EnumConstantDecl* ECD : ET->getDecl()->enumerators()) {
60
      // In Sema::CheckTemplateArugment, enum template arguments value are
61
      // extended to the size of the integer underlying the enum type.  This
62
      // may create a size difference between the enum value and template
63
      // argument value, requiring isSameValue here instead of operator==.
64
1.26k
      if (llvm::APSInt::isSameValue(ECD->getInitVal(), Val)) {
65
1.23k
        ECD->printQualifiedName(Out, Policy);
66
1.23k
        return;
67
1.23k
      }
68
1.26k
    }
69
1.23k
  }
70
197k
71
195k
  if (T->isBooleanType() && 
!Policy.MSVCFormatting86.1k
) {
72
51.6k
    Out << (Val.getBoolValue() ? 
"true"34.5k
: "false");
73
109k
  } else if (T->isCharType()) {
74
99
    const char Ch = Val.getZExtValue();
75
93
    Out << ((Ch == '\'') ? 
"'\\"6
: "'");
76
99
    Out.write_escaped(StringRef(&Ch, 1), /*UseHexEscapes=*/ true);
77
99
    Out << "'";
78
109k
  } else {
79
109k
    Out << Val;
80
109k
  }
81
195k
}
82
83
//===----------------------------------------------------------------------===//
84
// TemplateArgument Implementation
85
//===----------------------------------------------------------------------===//
86
87
TemplateArgument::TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value,
88
2.05M
                                   QualType Type) {
89
2.05M
  Integer.Kind = Integral;
90
  // Copy the APSInt value into our decomposed form.
91
2.05M
  Integer.BitWidth = Value.getBitWidth();
92
2.05M
  Integer.IsUnsigned = Value.isUnsigned();
93
  // If the value is large, we have to get additional memory from the ASTContext
94
2.05M
  unsigned NumWords = Value.getNumWords();
95
2.05M
  if (NumWords > 1) {
96
8
    void *Mem = Ctx.Allocate(NumWords * sizeof(uint64_t));
97
8
    std::memcpy(Mem, Value.getRawData(), NumWords * sizeof(uint64_t));
98
8
    Integer.pVal = static_cast<uint64_t *>(Mem);
99
2.05M
  } else {
100
2.05M
    Integer.VAL = Value.getZExtValue();
101
2.05M
  }
102
2.05M
103
2.05M
  Integer.Type = Type.getAsOpaquePtr();
104
2.05M
}
105
106
TemplateArgument
107
TemplateArgument::CreatePackCopy(ASTContext &Context,
108
532k
                                 ArrayRef<TemplateArgument> Args) {
109
532k
  if (Args.empty())
110
30.9k
    return getEmptyPack();
111
501k
112
501k
  return TemplateArgument(Args.copy(Context));
113
501k
}
114
115
29.2M
TemplateArgumentDependence TemplateArgument::getDependence() const {
116
29.2M
  auto Deps = TemplateArgumentDependence::None;
117
29.2M
  switch (getKind()) {
118
0
  case Null:
119
0
    llvm_unreachable("Should not have a NULL template argument");
120
0
121
22.8M
  case Type:
122
22.8M
    Deps = toTemplateArgumentDependence(getAsType()->getDependence());
123
22.8M
    if (isa<PackExpansionType>(getAsType()))
124
343k
      Deps |= TemplateArgumentDependence::Dependent;
125
22.8M
    return Deps;
126
0
127
108k
  case Template:
128
108k
    return toTemplateArgumentDependence(getAsTemplate().getDependence());
129
0
130
214
  case TemplateExpansion:
131
214
    return TemplateArgumentDependence::Dependent |
132
214
           TemplateArgumentDependence::Instantiation;
133
0
134
1.29k
  case Declaration: {
135
1.29k
    auto *DC = dyn_cast<DeclContext>(getAsDecl());
136
1.29k
    if (!DC)
137
1.24k
      DC = getAsDecl()->getDeclContext();
138
1.29k
    if (DC->isDependentContext())
139
0
      Deps = TemplateArgumentDependence::Dependent |
140
0
             TemplateArgumentDependence::Instantiation;
141
1.29k
    return Deps;
142
0
  }
143
0
144
646k
  case NullPtr:
145
646k
  case Integral:
146
646k
    return TemplateArgumentDependence::None;
147
646k
148
5.44M
  case Expression:
149
5.44M
    Deps = toTemplateArgumentDependence(getAsExpr()->getDependence());
150
5.44M
    if (isa<PackExpansionExpr>(getAsExpr()))
151
143k
      Deps |= TemplateArgumentDependence::Dependent |
152
143k
              TemplateArgumentDependence::Instantiation;
153
5.44M
    return Deps;
154
646k
155
221k
  case Pack:
156
221k
    for (const auto &P : pack_elements())
157
292k
      Deps |= P.getDependence();
158
221k
    return Deps;
159
0
  }
160
0
  llvm_unreachable("unhandled ArgKind");
161
0
}
162
163
6.81M
bool TemplateArgument::isDependent() const {
164
6.81M
  return getDependence() & TemplateArgumentDependence::Dependent;
165
6.81M
}
166
167
6.29M
bool TemplateArgument::isInstantiationDependent() const {
168
6.29M
  return getDependence() & TemplateArgumentDependence::Instantiation;
169
6.29M
}
170
171
26.7M
bool TemplateArgument::isPackExpansion() const {
172
26.7M
  switch (getKind()) {
173
1.58M
  case Null:
174
1.58M
  case Declaration:
175
1.58M
  case Integral:
176
1.58M
  case Pack:
177
1.58M
  case Template:
178
1.58M
  case NullPtr:
179
1.58M
    return false;
180
1.58M
181
189
  case TemplateExpansion:
182
189
    return true;
183
1.58M
184
20.2M
  case Type:
185
20.2M
    return isa<PackExpansionType>(getAsType());
186
1.58M
187
4.91M
  case Expression:
188
4.91M
    return isa<PackExpansionExpr>(getAsExpr());
189
0
  }
190
0
191
0
  llvm_unreachable("Invalid TemplateArgument Kind!");
192
0
}
193
194
775k
bool TemplateArgument::containsUnexpandedParameterPack() const {
195
775k
  return getDependence() & TemplateArgumentDependence::UnexpandedPack;
196
775k
}
197
198
147
Optional<unsigned> TemplateArgument::getNumTemplateExpansions() const {
199
147
  assert(getKind() == TemplateExpansion);
200
147
  if (TemplateArg.NumExpansions)
201
3
    return TemplateArg.NumExpansions - 1;
202
144
203
144
  return None;
204
144
}
205
206
80.5k
QualType TemplateArgument::getNonTypeTemplateArgumentType() const {
207
80.5k
  switch (getKind()) {
208
78.6k
  case TemplateArgument::Null:
209
78.6k
  case TemplateArgument::Type:
210
78.6k
  case TemplateArgument::Template:
211
78.6k
  case TemplateArgument::TemplateExpansion:
212
78.6k
  case TemplateArgument::Pack:
213
78.6k
    return QualType();
214
78.6k
215
208
  case TemplateArgument::Integral:
216
208
    return getIntegralType();
217
78.6k
218
1.64k
  case TemplateArgument::Expression:
219
1.64k
    return getAsExpr()->getType();
220
78.6k
221
8
  case TemplateArgument::Declaration:
222
8
    return getParamTypeForDecl();
223
78.6k
224
0
  case TemplateArgument::NullPtr:
225
0
    return getNullPtrType();
226
0
  }
227
0
228
0
  llvm_unreachable("Invalid TemplateArgument Kind!");
229
0
}
230
231
void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
232
32.4M
                               const ASTContext &Context) const {
233
32.4M
  ID.AddInteger(getKind());
234
32.4M
  switch (getKind()) {
235
0
  case Null:
236
0
    break;
237
0
238
24.1M
  case Type:
239
24.1M
    getAsType().Profile(ID);
240
24.1M
    break;
241
0
242
735
  case NullPtr:
243
735
    getNullPtrType().Profile(ID);
244
735
    break;
245
0
246
8.68k
  case Declaration:
247
8.68k
    ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : 
nullptr0
);
248
8.68k
    break;
249
0
250
56.8k
  case Template:
251
56.8k
  case TemplateExpansion: {
252
56.8k
    TemplateName Template = getAsTemplateOrTemplatePattern();
253
56.8k
    if (TemplateTemplateParmDecl *TTP
254
6.56k
          = dyn_cast_or_null<TemplateTemplateParmDecl>(
255
6.56k
                                                Template.getAsTemplateDecl())) {
256
6.56k
      ID.AddBoolean(true);
257
6.56k
      ID.AddInteger(TTP->getDepth());
258
6.56k
      ID.AddInteger(TTP->getPosition());
259
6.56k
      ID.AddBoolean(TTP->isParameterPack());
260
50.2k
    } else {
261
50.2k
      ID.AddBoolean(false);
262
50.2k
      ID.AddPointer(Context.getCanonicalTemplateName(Template)
263
50.2k
                                                          .getAsVoidPointer());
264
50.2k
    }
265
56.8k
    break;
266
56.8k
  }
267
56.8k
268
3.30M
  case Integral:
269
3.30M
    getAsIntegral().Profile(ID);
270
3.30M
    getIntegralType().Profile(ID);
271
3.30M
    break;
272
56.8k
273
3.70M
  case Expression:
274
3.70M
    getAsExpr()->Profile(ID, Context, true);
275
3.70M
    break;
276
56.8k
277
1.18M
  case Pack:
278
1.18M
    ID.AddInteger(Args.NumArgs);
279
3.03M
    for (unsigned I = 0; I != Args.NumArgs; 
++I1.85M
)
280
1.85M
      Args.Args[I].Profile(ID, Context);
281
32.4M
  }
282
32.4M
}
283
284
156k
bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const {
285
156k
  if (getKind() != Other.getKind()) 
return false0
;
286
156k
287
156k
  switch (getKind()) {
288
156k
  case Null:
289
156k
  case Type:
290
156k
  case Expression:
291
156k
  case Template:
292
156k
  case TemplateExpansion:
293
156k
  case NullPtr:
294
156k
    return TypeOrValue.V == Other.TypeOrValue.V;
295
156k
296
0
  case Declaration:
297
0
    return getAsDecl() == Other.getAsDecl();
298
156k
299
0
  case Integral:
300
0
    return getIntegralType() == Other.getIntegralType() &&
301
0
           getAsIntegral() == Other.getAsIntegral();
302
156k
303
0
  case Pack:
304
0
    if (Args.NumArgs != Other.Args.NumArgs) return false;
305
0
    for (unsigned I = 0, E = Args.NumArgs; I != E; ++I)
306
0
      if (!Args.Args[I].structurallyEquals(Other.Args.Args[I]))
307
0
        return false;
308
0
    return true;
309
0
  }
310
0
311
0
  llvm_unreachable("Invalid TemplateArgument Kind!");
312
0
}
313
314
68.5k
TemplateArgument TemplateArgument::getPackExpansionPattern() const {
315
68.5k
  assert(isPackExpansion());
316
68.5k
317
68.5k
  switch (getKind()) {
318
41.4k
  case Type:
319
41.4k
    return getAsType()->castAs<PackExpansionType>()->getPattern();
320
0
321
27.0k
  case Expression:
322
27.0k
    return cast<PackExpansionExpr>(getAsExpr())->getPattern();
323
0
324
54
  case TemplateExpansion:
325
54
    return TemplateArgument(getAsTemplateOrTemplatePattern());
326
0
327
0
  case Declaration:
328
0
  case Integral:
329
0
  case Pack:
330
0
  case Null:
331
0
  case Template:
332
0
  case NullPtr:
333
0
    return TemplateArgument();
334
0
  }
335
0
336
0
  llvm_unreachable("Invalid TemplateArgument Kind!");
337
0
}
338
339
void TemplateArgument::print(const PrintingPolicy &Policy,
340
1.40M
                             raw_ostream &Out) const {
341
1.40M
  switch (getKind()) {
342
95
  case Null:
343
95
    Out << "(no value)";
344
95
    break;
345
0
346
1.19M
  case Type: {
347
1.19M
    PrintingPolicy SubPolicy(Policy);
348
1.19M
    SubPolicy.SuppressStrongLifetime = true;
349
1.19M
    getAsType().print(Out, SubPolicy);
350
1.19M
    break;
351
0
  }
352
0
353
1.69k
  case Declaration: {
354
1.69k
    NamedDecl *ND = getAsDecl();
355
1.69k
    if (!getParamTypeForDecl()->isReferenceType())
356
1.37k
      Out << '&';
357
1.69k
    ND->printQualifiedName(Out);
358
1.69k
    break;
359
0
  }
360
0
361
868
  case NullPtr:
362
868
    Out << "nullptr";
363
868
    break;
364
0
365
1.07k
  case Template:
366
1.07k
    getAsTemplate().print(Out, Policy);
367
1.07k
    break;
368
0
369
2
  case TemplateExpansion:
370
2
    getAsTemplateOrTemplatePattern().print(Out, Policy);
371
2
    Out << "...";
372
2
    break;
373
0
374
197k
  case Integral:
375
197k
    printIntegral(*this, Out, Policy);
376
197k
    break;
377
0
378
8.39k
  case Expression:
379
8.39k
    getAsExpr()->printPretty(Out, nullptr, Policy);
380
8.39k
    break;
381
0
382
1.26k
  case Pack:
383
1.26k
    Out << "<";
384
1.26k
    bool First = true;
385
2.43k
    for (const auto &P : pack_elements()) {
386
2.43k
      if (First)
387
1.20k
        First = false;
388
1.22k
      else
389
1.22k
        Out << ", ";
390
2.43k
391
2.43k
      P.print(Policy, Out);
392
2.43k
    }
393
1.26k
    Out << ">";
394
1.26k
    break;
395
1.40M
  }
396
1.40M
}
397
398
0
void TemplateArgument::dump(raw_ostream &Out) const {
399
0
  LangOptions LO; // FIXME! see also TemplateName::dump().
400
0
  LO.CPlusPlus = true;
401
0
  LO.Bool = true;
402
0
  print(PrintingPolicy(LO), Out);
403
0
}
404
405
0
LLVM_DUMP_METHOD void TemplateArgument::dump() const { dump(llvm::errs()); }
406
407
//===----------------------------------------------------------------------===//
408
// TemplateArgumentLoc Implementation
409
//===----------------------------------------------------------------------===//
410
411
239k
SourceRange TemplateArgumentLoc::getSourceRange() const {
412
239k
  switch (Argument.getKind()) {
413
116k
  case TemplateArgument::Expression:
414
116k
    return getSourceExpression()->getSourceRange();
415
0
416
0
  case TemplateArgument::Declaration:
417
0
    return getSourceDeclExpression()->getSourceRange();
418
0
419
0
  case TemplateArgument::NullPtr:
420
0
    return getSourceNullPtrExpression()->getSourceRange();
421
0
422
122k
  case TemplateArgument::Type:
423
122k
    if (TypeSourceInfo *TSI = getTypeSourceInfo())
424
122k
      return TSI->getTypeLoc().getSourceRange();
425
0
    else
426
0
      return SourceRange();
427
0
428
248
  case TemplateArgument::Template:
429
248
    if (getTemplateQualifierLoc())
430
43
      return SourceRange(getTemplateQualifierLoc().getBeginLoc(),
431
43
                         getTemplateNameLoc());
432
205
    return SourceRange(getTemplateNameLoc());
433
205
434
2
  case TemplateArgument::TemplateExpansion:
435
2
    if (getTemplateQualifierLoc())
436
1
      return SourceRange(getTemplateQualifierLoc().getBeginLoc(),
437
1
                         getTemplateEllipsisLoc());
438
1
    return SourceRange(getTemplateNameLoc(), getTemplateEllipsisLoc());
439
1
440
0
  case TemplateArgument::Integral:
441
0
    return getSourceIntegralExpression()->getSourceRange();
442
1
443
0
  case TemplateArgument::Pack:
444
0
  case TemplateArgument::Null:
445
0
    return SourceRange();
446
0
  }
447
0
448
0
  llvm_unreachable("Invalid TemplateArgument Kind!");
449
0
}
450
451
const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
452
957
                                           const TemplateArgument &Arg) {
453
957
  switch (Arg.getKind()) {
454
0
  case TemplateArgument::Null:
455
    // This is bad, but not as bad as crashing because of argument
456
    // count mismatches.
457
0
    return DB << "(null template argument)";
458
0
459
359
  case TemplateArgument::Type:
460
359
    return DB << Arg.getAsType();
461
0
462
8
  case TemplateArgument::Declaration:
463
8
    return DB << Arg.getAsDecl();
464
0
465
0
  case TemplateArgument::NullPtr:
466
0
    return DB << "nullptr";
467
0
468
44
  case TemplateArgument::Integral:
469
44
    return DB << Arg.getAsIntegral().toString(10);
470
0
471
14
  case TemplateArgument::Template:
472
14
    return DB << Arg.getAsTemplate();
473
0
474
0
  case TemplateArgument::TemplateExpansion:
475
0
    return DB << Arg.getAsTemplateOrTemplatePattern() << "...";
476
0
477
406
  case TemplateArgument::Expression: {
478
    // This shouldn't actually ever happen, so it's okay that we're
479
    // regurgitating an expression here.
480
    // FIXME: We're guessing at LangOptions!
481
406
    SmallString<32> Str;
482
406
    llvm::raw_svector_ostream OS(Str);
483
406
    LangOptions LangOpts;
484
406
    LangOpts.CPlusPlus = true;
485
406
    PrintingPolicy Policy(LangOpts);
486
406
    Arg.getAsExpr()->printPretty(OS, nullptr, Policy);
487
406
    return DB << OS.str();
488
0
  }
489
0
490
126
  case TemplateArgument::Pack: {
491
    // FIXME: We're guessing at LangOptions!
492
126
    SmallString<32> Str;
493
126
    llvm::raw_svector_ostream OS(Str);
494
126
    LangOptions LangOpts;
495
126
    LangOpts.CPlusPlus = true;
496
126
    PrintingPolicy Policy(LangOpts);
497
126
    Arg.print(Policy, OS);
498
126
    return DB << OS.str();
499
0
  }
500
0
  }
501
0
502
0
  llvm_unreachable("Invalid TemplateArgument Kind!");
503
0
}
504
505
const ASTTemplateArgumentListInfo *
506
ASTTemplateArgumentListInfo::Create(const ASTContext &C,
507
171k
                                    const TemplateArgumentListInfo &List) {
508
171k
  std::size_t size = totalSizeToAlloc<TemplateArgumentLoc>(List.size());
509
171k
  void *Mem = C.Allocate(size, alignof(ASTTemplateArgumentListInfo));
510
171k
  return new (Mem) ASTTemplateArgumentListInfo(List);
511
171k
}
512
513
ASTTemplateArgumentListInfo::ASTTemplateArgumentListInfo(
514
171k
    const TemplateArgumentListInfo &Info) {
515
171k
  LAngleLoc = Info.getLAngleLoc();
516
171k
  RAngleLoc = Info.getRAngleLoc();
517
171k
  NumTemplateArgs = Info.size();
518
171k
519
171k
  TemplateArgumentLoc *ArgBuffer = getTrailingObjects<TemplateArgumentLoc>();
520
538k
  for (unsigned i = 0; i != NumTemplateArgs; 
++i366k
)
521
366k
    new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]);
522
171k
}
523
524
void ASTTemplateKWAndArgsInfo::initializeFrom(
525
    SourceLocation TemplateKWLoc, const TemplateArgumentListInfo &Info,
526
17.1k
    TemplateArgumentLoc *OutArgArray) {
527
17.1k
  this->TemplateKWLoc = TemplateKWLoc;
528
17.1k
  LAngleLoc = Info.getLAngleLoc();
529
17.1k
  RAngleLoc = Info.getRAngleLoc();
530
17.1k
  NumTemplateArgs = Info.size();
531
17.1k
532
37.1k
  for (unsigned i = 0; i != NumTemplateArgs; 
++i20.0k
)
533
20.0k
    new (&OutArgArray[i]) TemplateArgumentLoc(Info[i]);
534
17.1k
}
535
536
179
void ASTTemplateKWAndArgsInfo::initializeFrom(SourceLocation TemplateKWLoc) {
537
179
  assert(TemplateKWLoc.isValid());
538
179
  LAngleLoc = SourceLocation();
539
179
  RAngleLoc = SourceLocation();
540
179
  this->TemplateKWLoc = TemplateKWLoc;
541
179
  NumTemplateArgs = 0;
542
179
}
543
544
void ASTTemplateKWAndArgsInfo::initializeFrom(
545
    SourceLocation TemplateKWLoc, const TemplateArgumentListInfo &Info,
546
525k
    TemplateArgumentLoc *OutArgArray, TemplateArgumentDependence &Deps) {
547
525k
  this->TemplateKWLoc = TemplateKWLoc;
548
525k
  LAngleLoc = Info.getLAngleLoc();
549
525k
  RAngleLoc = Info.getRAngleLoc();
550
525k
  NumTemplateArgs = Info.size();
551
525k
552
1.14M
  for (unsigned i = 0; i != NumTemplateArgs; 
++i620k
) {
553
620k
    Deps |= Info[i].getArgument().getDependence();
554
620k
555
620k
    new (&OutArgArray[i]) TemplateArgumentLoc(Info[i]);
556
620k
  }
557
525k
}
558
559
void ASTTemplateKWAndArgsInfo::copyInto(const TemplateArgumentLoc *ArgArray,
560
281k
                                        TemplateArgumentListInfo &Info) const {
561
281k
  Info.setLAngleLoc(LAngleLoc);
562
281k
  Info.setRAngleLoc(RAngleLoc);
563
595k
  for (unsigned I = 0; I != NumTemplateArgs; 
++I313k
)
564
313k
    Info.addArgument(ArgArray[I]);
565
281k
}